Merge commit 'dc2ae12' into master

This merges dc2ae123784cf1a9504d6b4eba112170574e31e0 from
upstream-main and establishes history between main and upstream-main.
There are no changes in the sources used to build the libraries used
in Android.

Changes in this commit are
- Updated cmake/libgav1_build_definitions.cmake to match upstream-main
- Updated METADATA to include GIT url path

Bug: 211157723
Test: Builds
Change-Id: I2f65e4c580d539b8ead9360b18888b54f8a18a3c
diff --git a/.cmake-format.py b/.cmake-format.py
new file mode 100644
index 0000000..90499e5
--- /dev/null
+++ b/.cmake-format.py
@@ -0,0 +1,126 @@
+# Generated with cmake-format 0.5.4
+# --------------------------
+# General Formatting Options
+# --------------------------
+# How wide to allow formatted cmake files
+line_width = 80
+
+# How many spaces to tab for indent
+tab_size = 2
+
+# If arglists are longer than this, break them always
+max_subargs_per_line = 10
+
+# If true, separate flow control names from their parentheses with a space
+separate_ctrl_name_with_space = False
+
+# If true, separate function names from parentheses with a space
+separate_fn_name_with_space = False
+
+# If a statement is wrapped to more than one line, than dangle the closing
+# parenthesis on it's own line
+dangle_parens = False
+
+# If the statement spelling length (including space and parenthesis is larger
+# than the tab width by more than this amoung, then force reject un-nested
+# layouts.
+max_prefix_chars = 2
+
+# If a candidate layout is wrapped horizontally but it exceeds this many lines,
+# then reject the layout.
+max_lines_hwrap = 2
+
+# What style line endings to use in the output.
+line_ending = 'unix'
+
+# Format command names consistently as 'lower' or 'upper' case
+command_case = 'lower'
+
+# Format keywords consistently as 'lower' or 'upper' case
+keyword_case = 'unchanged'
+
+# Specify structure for custom cmake functions
+additional_commands = {
+  "foo": {
+    "flags": [
+      "BAR",
+      "BAZ"
+    ],
+    "kwargs": {
+      "HEADERS": "*",
+      "SOURCES": "*",
+      "DEPENDS": "*"
+    }
+  }
+}
+
+# A list of command names which should always be wrapped
+always_wrap = []
+
+# Specify the order of wrapping algorithms during successive reflow attempts
+algorithm_order = [0, 1, 2, 3, 4]
+
+# If true, the argument lists which are known to be sortable will be sorted
+# lexicographicall
+enable_sort = False
+
+# If true, the parsers may infer whether or not an argument list is sortable
+# (without annotation).
+autosort = False
+
+# If a comment line starts with at least this many consecutive hash characters,
+# then don't lstrip() them off. This allows for lazy hash rulers where the first
+# hash char is not separated by space
+hashruler_min_length = 10
+
+# A dictionary containing any per-command configuration overrides. Currently
+# only `command_case` is supported.
+per_command = {}
+
+
+# --------------------------
+# Comment Formatting Options
+# --------------------------
+# What character to use for bulleted lists
+bullet_char = '*'
+
+# What character to use as punctuation after numerals in an enumerated list
+enum_char = '.'
+
+# enable comment markup parsing and reflow
+enable_markup = True
+
+# If comment markup is enabled, don't reflow the first comment block in each
+# listfile. Use this to preserve formatting of your copyright/license
+# statements.
+first_comment_is_literal = True
+
+# If comment markup is enabled, don't reflow any comment block which matches
+# this (regex) pattern. Default is `None` (disabled).
+literal_comment_pattern = None
+
+# Regular expression to match preformat fences in comments
+# default=r'^\s*([`~]{3}[`~]*)(.*)$'
+fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
+
+# Regular expression to match rulers in comments
+# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
+ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
+
+# If true, then insert a space between the first hash char and remaining hash
+# chars in a hash ruler, and normalize it's length to fill the column
+canonicalize_hashrulers = True
+
+
+# ---------------------------------
+# Miscellaneous Options
+# ---------------------------------
+# If true, emit the unicode byte-order mark (BOM) at the start of the file
+emit_byteorder_mark = False
+
+# Specify the encoding of the input file. Defaults to utf-8.
+input_encoding = 'utf-8'
+
+# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
+# only claims to support utf-8 so be careful when using anything else
+output_encoding = 'utf-8'
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b934084
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* whitespace=tab-in-indent,space-before-tab,trailing-space
diff --git a/libgav1/.gitignore b/.gitignore
similarity index 100%
rename from libgav1/.gitignore
rename to .gitignore
diff --git a/METADATA b/METADATA
index 342cd15..3710207 100644
--- a/METADATA
+++ b/METADATA
@@ -8,8 +8,14 @@
     value: "http://go/libgav1-doc"
   }
   url {
-    type: PIPER
-    value: "//depot/google3/third_party/libgav1"
+    type: GIT
+    value: "https://chromium.googlesource.com/codecs/libgav1"
   }
+  version: "dc2ae123784cf1a9504d6b4eba112170574e31e0"
   license_type: NOTICE
+  last_upgrade_date {
+    year: 2022
+    month: 10
+    day: 4
+  }
 }
diff --git a/cmake/libgav1_build_definitions.cmake b/cmake/libgav1_build_definitions.cmake
index 3885dcd..95c17be 100644
--- a/cmake/libgav1_build_definitions.cmake
+++ b/cmake/libgav1_build_definitions.cmake
@@ -31,8 +31,8 @@
   # passed to libtool.
   #
   # We set LIBGAV1_SOVERSION = [c-a].a.r
-  set(LT_CURRENT 0)
-  set(LT_REVISION 1)
+  set(LT_CURRENT 1)
+  set(LT_REVISION 0)
   set(LT_AGE 0)
   math(EXPR LIBGAV1_SOVERSION_MAJOR "${LT_CURRENT} - ${LT_AGE}")
   set(LIBGAV1_SOVERSION "${LIBGAV1_SOVERSION_MAJOR}.${LT_AGE}.${LT_REVISION}")
diff --git a/examples/file_reader_factory_test.cc b/examples/file_reader_factory_test.cc
new file mode 100644
index 0000000..346f9f8
--- /dev/null
+++ b/examples/file_reader_factory_test.cc
@@ -0,0 +1,114 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "examples/file_reader_factory.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+#include <string>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "examples/file_reader_interface.h"
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+class AlwaysFailFileReader : public FileReaderInterface {
+ public:
+  static std::unique_ptr<FileReaderInterface> Open(
+      const std::string& /*file_name*/, bool /*error_tolerant*/) {
+    return nullptr;
+  }
+
+  AlwaysFailFileReader() = delete;
+  AlwaysFailFileReader(const AlwaysFailFileReader&) = delete;
+  AlwaysFailFileReader& operator=(const AlwaysFailFileReader&) = delete;
+  // Note this isn't overridden as the class can never be instantiated. This
+  // avoids an unused function warning.
+  // ~AlwaysFailFileReader() override = default;
+
+  bool ReadTemporalUnit(std::vector<uint8_t>* /*data*/,
+                        int64_t* /*pts*/) override {
+    return false;
+  }
+  bool IsEndOfFile() const override { return false; }
+
+  size_t width() const override { return 0; }
+  size_t height() const override { return 0; }
+  size_t frame_rate() const override { return 0; }
+  size_t time_scale() const override { return 0; }
+
+  static bool is_registered_;
+};
+
+class AlwaysOkFileReader : public FileReaderInterface {
+ public:
+  static std::unique_ptr<FileReaderInterface> Open(
+      const std::string& /*file_name*/, bool /*error_tolerant*/) {
+    auto reader = absl::WrapUnique(new (std::nothrow) AlwaysOkFileReader());
+
+    return reader;
+  }
+
+  AlwaysOkFileReader(const AlwaysOkFileReader&) = delete;
+  AlwaysOkFileReader& operator=(const AlwaysOkFileReader&) = delete;
+  ~AlwaysOkFileReader() override = default;
+
+  bool ReadTemporalUnit(std::vector<uint8_t>* /*data*/,
+                        int64_t* /*pts*/) override {
+    return true;
+  }
+  bool IsEndOfFile() const override { return true; }
+
+  size_t width() const override { return 1; }
+  size_t height() const override { return 1; }
+  size_t frame_rate() const override { return 1; }
+  size_t time_scale() const override { return 1; }
+
+  static bool is_registered_;
+
+ private:
+  AlwaysOkFileReader() = default;
+};
+
+bool AlwaysFailFileReader::is_registered_ =
+    FileReaderFactory::RegisterReader(AlwaysFailFileReader::Open);
+
+bool AlwaysOkFileReader::is_registered_ =
+    FileReaderFactory::RegisterReader(AlwaysOkFileReader::Open);
+
+TEST(FileReaderFactoryTest, RegistrationFail) {
+  EXPECT_FALSE(FileReaderFactory::RegisterReader(nullptr));
+}
+
+TEST(FileReaderFactoryTest, OpenReader) {
+  ASSERT_TRUE(AlwaysOkFileReader::is_registered_);
+  ASSERT_TRUE(AlwaysFailFileReader::is_registered_);
+
+  auto reader = FileReaderFactory::OpenReader("fake file");
+  EXPECT_NE(reader, nullptr);
+  EXPECT_TRUE(reader->IsEndOfFile());
+  EXPECT_TRUE(reader->ReadTemporalUnit(nullptr, nullptr));
+  EXPECT_EQ(reader->width(), 1);
+  EXPECT_EQ(reader->height(), 1);
+  EXPECT_EQ(reader->frame_rate(), 1);
+  EXPECT_EQ(reader->time_scale(), 1);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/examples/file_reader_test.cc b/examples/file_reader_test.cc
new file mode 100644
index 0000000..53e27f7
--- /dev/null
+++ b/examples/file_reader_test.cc
@@ -0,0 +1,126 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "examples/file_reader.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <memory>
+#include <vector>
+
+#include "examples/file_reader_interface.h"
+#include "examples/file_reader_test_common.h"
+#include "gtest/gtest.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace {
+
+// For use with tests that expect Open() failure to distinguish failure due to
+// the file contents versus failure due to a missing file.
+bool FileCanBeRead(const std::string& filename) {
+  FILE* const file = fopen(filename.c_str(), "r");
+  if (file != nullptr) {
+    fclose(file);
+    return true;
+  }
+  return false;
+}
+
+TEST(FileReaderTest, FailOpen) {
+  EXPECT_EQ(FileReader::Open(""), nullptr);
+  const std::string filename =
+      test_utils::GetTestInputFilePath("ivf-signature-only");
+  SCOPED_TRACE("Filename: " + filename);
+  EXPECT_TRUE(FileCanBeRead(filename));
+  EXPECT_EQ(FileReader::Open(filename), nullptr);
+}
+
+TEST(FileReaderTest, Open) {
+  const std::string filenames[] = {
+      test_utils::GetTestInputFilePath("five-frames.ivf"),
+      test_utils::GetTestInputFilePath("ivf-header-and-truncated-frame-header"),
+      test_utils::GetTestInputFilePath("ivf-header-only"),
+      test_utils::GetTestInputFilePath("one-frame-truncated.ivf"),
+      test_utils::GetTestInputFilePath("one-frame.ivf"),
+  };
+  for (const auto& filename : filenames) {
+    EXPECT_NE(FileReader::Open(filename), nullptr) << "Filename: " << filename;
+  }
+}
+
+TEST_P(FileReaderFailTest, FailRead) {
+  ASSERT_FALSE(reader_->ReadTemporalUnit(&tu_data_, nullptr));
+}
+
+TEST_P(FileReaderErrorTolerant, ReadThroughEndOfFile) {
+  while (!reader_->IsEndOfFile()) {
+    tu_data_.clear();
+    ASSERT_TRUE(reader_->ReadTemporalUnit(&tu_data_, nullptr));
+    ASSERT_GT(tu_data_.size(), 0);
+  }
+}
+
+TEST_P(FileReaderTestNoTimeStamps, ReadThroughEndOfFile) {
+  while (!reader_->IsEndOfFile()) {
+    tu_data_.clear();
+    ASSERT_TRUE(reader_->ReadTemporalUnit(&tu_data_, nullptr));
+  }
+}
+
+TEST_P(FileReaderTestWithTimeStamps, ReadThroughEndOfFile) {
+  int64_t timestamp = 0;
+  while (!reader_->IsEndOfFile()) {
+    tu_data_.clear();
+    ASSERT_TRUE(reader_->ReadTemporalUnit(&tu_data_, &timestamp));
+    if (!tu_data_.empty()) {
+      last_timestamp_ = timestamp;
+    }
+  }
+  ASSERT_TRUE(tu_data_.empty());
+  ASSERT_EQ(last_timestamp_, expected_last_timestamp_);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    FailRead, FileReaderFailTest,
+    testing::Values(
+        FileReaderTestParameters(FileReader::Open,
+                                 "ivf-header-and-truncated-frame-header"),
+        FileReaderTestParameters(FileReader::Open, "one-frame-truncated.ivf")));
+
+INSTANTIATE_TEST_SUITE_P(ReadThroughEndOfFile, FileReaderErrorTolerant,
+                         testing::Values(FileReaderTestParameters(
+                             FileReader::Open, "one-frame-truncated.ivf")));
+
+INSTANTIATE_TEST_SUITE_P(
+    ReadThroughEndOfFile, FileReaderTestNoTimeStamps,
+    testing::Values(FileReaderTestParameters(FileReader::Open, "one-frame.ivf"),
+                    FileReaderTestParameters(FileReader::Open,
+                                             "one-frame-large-timestamp.ivf"),
+                    FileReaderTestParameters(FileReader::Open,
+                                             "five-frames.ivf")));
+
+INSTANTIATE_TEST_SUITE_P(
+    ReadThroughEndOfFile, FileReaderTestWithTimeStamps,
+    testing::Values(
+        FileReaderTestWithTimeStampsParameters(FileReader::Open,
+                                               "one-frame.ivf", 0),
+        FileReaderTestWithTimeStampsParameters(FileReader::Open,
+                                               "one-frame-large-timestamp.ivf",
+                                               4294967296),
+        FileReaderTestWithTimeStampsParameters(FileReader::Open,
+                                               "five-frames.ivf", 4)));
+
+}  // namespace
+}  // namespace libgav1
diff --git a/examples/file_reader_test_common.cc b/examples/file_reader_test_common.cc
new file mode 100644
index 0000000..735dd9e
--- /dev/null
+++ b/examples/file_reader_test_common.cc
@@ -0,0 +1,43 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "examples/file_reader_test_common.h"
+
+#include <ostream>
+
+#include "examples/file_reader.h"
+
+namespace libgav1 {
+
+std::ostream& operator<<(std::ostream& stream,
+                         const FileReaderTestParameters& parameters) {
+  stream << "open_function="
+         << ((parameters.open_function == FileReader::Open) ? "FileReader"
+                                                            : "Unknown")
+         << ", file_name=" << parameters.file_name;
+  return stream;
+}
+
+std::ostream& operator<<(
+    std::ostream& stream,
+    const FileReaderTestWithTimeStampsParameters& parameters) {
+  stream << "open_function="
+         << ((parameters.open_function == FileReader::Open) ? "FileReader"
+                                                            : "Unknown")
+         << ", file_name=" << parameters.file_name
+         << ", expected_last_timestamp=" << parameters.expected_last_timestamp;
+  return stream;
+}
+
+}  // namespace libgav1
diff --git a/examples/file_reader_test_common.h b/examples/file_reader_test_common.h
new file mode 100644
index 0000000..187a6ac
--- /dev/null
+++ b/examples/file_reader_test_common.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2021 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBGAV1_EXAMPLES_FILE_READER_TEST_COMMON_H_
+#define LIBGAV1_EXAMPLES_FILE_READER_TEST_COMMON_H_
+
+#include <cstdint>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "examples/file_reader.h"
+#include "examples/file_reader_factory.h"
+#include "examples/file_reader_interface.h"
+#include "gtest/gtest.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+
+struct FileReaderTestParameters {
+  FileReaderTestParameters() = default;
+  FileReaderTestParameters(FileReaderFactory::OpenFunction open_function,
+                           const char* file_name)
+      : open_function(open_function), file_name(file_name) {}
+  FileReaderTestParameters(const FileReaderTestParameters&) = default;
+  FileReaderTestParameters& operator=(const FileReaderTestParameters&) = delete;
+  FileReaderTestParameters(FileReaderTestParameters&&) = default;
+  FileReaderTestParameters& operator=(FileReaderTestParameters&&) = default;
+  ~FileReaderTestParameters() = default;
+
+  FileReaderFactory::OpenFunction open_function = nullptr;
+  const char* file_name = nullptr;
+};
+
+class FileReaderTestBase {
+ public:
+  FileReaderTestBase() = default;
+  FileReaderTestBase(const FileReaderTestBase&) = delete;
+  FileReaderTestBase& operator=(const FileReaderTestBase&) = delete;
+  FileReaderTestBase(FileReaderTestBase&&) = default;
+  FileReaderTestBase& operator=(FileReaderTestBase&&) = default;
+  ~FileReaderTestBase() = default;
+
+ protected:
+  void OpenReader(const char* file_name,
+                  FileReaderFactory::OpenFunction open_function) {
+    file_name_ = test_utils::GetTestInputFilePath(file_name);
+    reader_ = open_function(file_name_, /*error_tolerant=*/false);
+    ASSERT_NE(reader_, nullptr);
+  }
+
+  std::string file_name_;
+  std::unique_ptr<FileReaderInterface> reader_;
+  std::vector<uint8_t> tu_data_;
+};
+
+class FileReaderFailTest
+    : public FileReaderTestBase,
+      public testing::TestWithParam<FileReaderTestParameters> {
+ public:
+  FileReaderFailTest() = default;
+  FileReaderFailTest(const FileReaderTestBase&) = delete;
+  FileReaderFailTest& operator=(const FileReaderTestBase&) = delete;
+  ~FileReaderFailTest() override = default;
+
+ protected:
+  void SetUp() override {
+    OpenReader(GetParam().file_name, GetParam().open_function);
+  }
+};
+
+class FileReaderTestNoTimeStamps
+    : public FileReaderTestBase,
+      public testing::TestWithParam<FileReaderTestParameters> {
+ public:
+  FileReaderTestNoTimeStamps() = default;
+  FileReaderTestNoTimeStamps(const FileReaderTestNoTimeStamps&) = delete;
+  FileReaderTestNoTimeStamps& operator=(const FileReaderTestNoTimeStamps&) =
+      delete;
+  ~FileReaderTestNoTimeStamps() override = default;
+
+ protected:
+  void SetUp() override {
+    OpenReader(GetParam().file_name, GetParam().open_function);
+  }
+};
+
+class FileReaderErrorTolerant
+    : public FileReaderTestBase,
+      public testing::TestWithParam<FileReaderTestParameters> {
+ public:
+  FileReaderErrorTolerant() = default;
+  FileReaderErrorTolerant(const FileReaderErrorTolerant&) = delete;
+  FileReaderErrorTolerant& operator=(const FileReaderErrorTolerant&) = delete;
+  ~FileReaderErrorTolerant() override = default;
+
+ protected:
+  void SetUp() override {
+    file_name_ = test_utils::GetTestInputFilePath(GetParam().file_name);
+    reader_ = GetParam().open_function(file_name_, /*error_tolerant=*/true);
+    ASSERT_NE(reader_, nullptr);
+  }
+};
+
+struct FileReaderTestWithTimeStampsParameters {
+  FileReaderTestWithTimeStampsParameters() = default;
+  FileReaderTestWithTimeStampsParameters(
+      FileReaderFactory::OpenFunction open_function, const char* file_name,
+      int64_t expected_last_timestamp)
+      : open_function(open_function),
+        file_name(file_name),
+        expected_last_timestamp(expected_last_timestamp) {}
+  FileReaderTestWithTimeStampsParameters(
+      const FileReaderTestWithTimeStampsParameters&) = default;
+  FileReaderTestWithTimeStampsParameters& operator=(
+      const FileReaderTestWithTimeStampsParameters&) = delete;
+  FileReaderTestWithTimeStampsParameters(
+      FileReaderTestWithTimeStampsParameters&&) = default;
+  FileReaderTestWithTimeStampsParameters& operator=(
+      FileReaderTestWithTimeStampsParameters&&) = default;
+  ~FileReaderTestWithTimeStampsParameters() = default;
+
+  FileReaderFactory::OpenFunction open_function = nullptr;
+  const char* file_name = nullptr;
+  int64_t expected_last_timestamp = 0;
+};
+
+std::ostream& operator<<(std::ostream& stream,
+                         const FileReaderTestParameters& parameters);
+
+std::ostream& operator<<(
+    std::ostream& stream,
+    const FileReaderTestWithTimeStampsParameters& parameters);
+
+class FileReaderTestWithTimeStamps
+    : public FileReaderTestBase,
+      public testing::TestWithParam<FileReaderTestWithTimeStampsParameters> {
+ public:
+  FileReaderTestWithTimeStamps() = default;
+  FileReaderTestWithTimeStamps(const FileReaderTestWithTimeStamps&) = delete;
+  FileReaderTestWithTimeStamps& operator=(const FileReaderTestWithTimeStamps&) =
+      delete;
+  ~FileReaderTestWithTimeStamps() override = default;
+
+ protected:
+  void SetUp() override {
+    FileReaderTestWithTimeStampsParameters parameters = GetParam();
+    OpenReader(parameters.file_name, parameters.open_function);
+    expected_last_timestamp_ = parameters.expected_last_timestamp;
+  }
+
+  int64_t last_timestamp_ = 0;
+  int64_t expected_last_timestamp_ = 0;
+};
+
+}  // namespace libgav1
+#endif  // LIBGAV1_EXAMPLES_FILE_READER_TEST_COMMON_H_
diff --git a/examples/file_writer_test.cc b/examples/file_writer_test.cc
new file mode 100644
index 0000000..481808c
--- /dev/null
+++ b/examples/file_writer_test.cc
@@ -0,0 +1,495 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "examples/file_writer.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "gav1/decoder_buffer.h"
+#include "gtest/gtest.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace {
+
+const char kExpectedY4mHeader8bit[] = "YUV4MPEG2 W352 H288 F30:1 Ip C420jpeg\n";
+const char kExpectedY4mHeader10bit[] = "YUV4MPEG2 W352 H288 F30:1 Ip C420p10\n";
+const char kExpectedY4mHeader8bitMonochrome[] =
+    "YUV4MPEG2 W352 H288 F30:1 Ip Cmono\n";
+const char kExpectedY4mHeader10bitMonochrome[] =
+    "YUV4MPEG2 W352 H288 F30:1 Ip Cmono10\n";
+
+// Note: These are non-const because DecoderBuffer.plane is non-const.
+char fake_plane0[] = "PLANE0\n";
+char fake_plane1[] = "PLANE1\n";
+char fake_plane2[] = "PLANE2\n";
+
+constexpr size_t kExpectedRawDataBufferCount = 3;
+const char* kExpectedRawData[kExpectedRawDataBufferCount] = {
+    fake_plane0, fake_plane1, fake_plane2};
+
+const char* const kExpectedRawDataMonochrome = fake_plane0;
+
+constexpr size_t kExpectedY4mDataBufferCount = 5;
+const char* const kExpectedY4mFileData8bit[kExpectedY4mDataBufferCount] = {
+    kExpectedY4mHeader8bit, "FRAME\n", fake_plane0, fake_plane1, fake_plane2};
+const char* const kExpectedY4mFileData10bit[kExpectedY4mDataBufferCount] = {
+    kExpectedY4mHeader10bit, "FRAME\n", fake_plane0, fake_plane1, fake_plane2};
+
+constexpr size_t kExpectedY4mDataBufferCountMonochrome = 3;
+const char* const
+    kExpectedY4mFileData8bitMonochrome[kExpectedY4mDataBufferCountMonochrome] =
+        {kExpectedY4mHeader8bitMonochrome, "FRAME\n", fake_plane0};
+const char* const
+    kExpectedY4mFileData10bitMonochrome[kExpectedY4mDataBufferCountMonochrome] =
+        {kExpectedY4mHeader10bitMonochrome, "FRAME\n", fake_plane0};
+
+// TODO(tomfinegan): Add a bitdepth arg, and test writing 10 bit frame buffers.
+std::unique_ptr<DecoderBuffer> GetFakeDecoderBuffer(ImageFormat image_format) {
+  auto buffer = absl::make_unique<DecoderBuffer>();
+  if (buffer == nullptr) return nullptr;
+  buffer->chroma_sample_position = kChromaSamplePositionUnknown;
+  buffer->image_format = image_format;
+  buffer->bitdepth = 8;
+  buffer->displayed_width[0] = static_cast<int>(strlen(fake_plane0));
+  buffer->displayed_width[1] = static_cast<int>(strlen(fake_plane1));
+  buffer->displayed_width[2] = static_cast<int>(strlen(fake_plane2));
+  buffer->displayed_height[0] = 1;
+  buffer->displayed_height[1] = 1;
+  buffer->displayed_height[2] = 1;
+  buffer->stride[0] = static_cast<int>(strlen(fake_plane0));
+  buffer->stride[1] = static_cast<int>(strlen(fake_plane1));
+  buffer->stride[2] = static_cast<int>(strlen(fake_plane2));
+  buffer->plane[0] = reinterpret_cast<uint8_t*>(fake_plane0);
+  buffer->plane[1] = reinterpret_cast<uint8_t*>(fake_plane1);
+  buffer->plane[2] = reinterpret_cast<uint8_t*>(fake_plane2);
+  buffer->user_private_data = 0;
+  buffer->buffer_private_data = nullptr;
+  return buffer;
+}
+
+TEST(FileWriterTest, FailOpen) {
+  EXPECT_EQ(FileWriter::Open(test_utils::GetTestOutputFilePath("fail_open"),
+                             static_cast<FileWriter::FileType>(3), nullptr),
+            nullptr);
+  EXPECT_EQ(FileWriter::Open(test_utils::GetTestOutputFilePath("fail_open"),
+                             FileWriter::kFileTypeY4m, nullptr),
+            nullptr);
+}
+
+struct FileWriterY4mHeaderTestParameters {
+  FileWriterY4mHeaderTestParameters() = default;
+  FileWriterY4mHeaderTestParameters(const FileWriterY4mHeaderTestParameters&) =
+      default;
+  FileWriterY4mHeaderTestParameters& operator=(
+      const FileWriterY4mHeaderTestParameters&) = default;
+  FileWriterY4mHeaderTestParameters(FileWriterY4mHeaderTestParameters&&) =
+      default;
+  FileWriterY4mHeaderTestParameters& operator=(
+      FileWriterY4mHeaderTestParameters&&) = default;
+  ~FileWriterY4mHeaderTestParameters() = default;
+
+  FileWriterY4mHeaderTestParameters(std::string file_name,
+                                    ChromaSamplePosition chroma_sample_position,
+                                    ImageFormat image_format, int bitdepth,
+                                    const char* expected_header_string)
+      : file_name(std::move(file_name)),
+        chroma_sample_position(chroma_sample_position),
+        image_format(image_format),
+        bitdepth(bitdepth),
+        expected_header_string(expected_header_string) {}
+  std::string file_name;
+  ChromaSamplePosition chroma_sample_position = kChromaSamplePositionUnknown;
+  ImageFormat image_format = kImageFormatMonochrome400;
+  int bitdepth = 8;
+  const char* expected_header_string = nullptr;
+};
+
+std::ostream& operator<<(std::ostream& stream,
+                         const FileWriterY4mHeaderTestParameters& parameters) {
+  stream << "file_name=" << parameters.file_name << "\n"
+         << "chroma_sample_position=" << parameters.chroma_sample_position
+         << "\n"
+         << "image_format=" << parameters.image_format << "\n"
+         << "bitdepth=" << parameters.bitdepth << "\n"
+         << "expected_header_string=" << parameters.expected_header_string
+         << "\n";
+  return stream;
+}
+
+class FileWriterY4mHeaderTest
+    : public testing::TestWithParam<FileWriterY4mHeaderTestParameters> {
+ public:
+  FileWriterY4mHeaderTest() {
+    test_parameters_ = GetParam();
+    y4m_parameters_.width = 352;
+    y4m_parameters_.height = 288;
+    y4m_parameters_.frame_rate_numerator = 30;
+    y4m_parameters_.frame_rate_denominator = 1;
+    y4m_parameters_.chroma_sample_position =
+        test_parameters_.chroma_sample_position;
+    y4m_parameters_.image_format = test_parameters_.image_format;
+    y4m_parameters_.bitdepth = test_parameters_.bitdepth;
+  }
+  FileWriterY4mHeaderTest(const FileWriterY4mHeaderTest&) = delete;
+  FileWriterY4mHeaderTest& operator=(const FileWriterY4mHeaderTest&) = delete;
+  ~FileWriterY4mHeaderTest() override = default;
+
+ protected:
+  FileWriterY4mHeaderTestParameters test_parameters_;
+  FileWriter::Y4mParameters y4m_parameters_;
+};
+
+TEST_P(FileWriterY4mHeaderTest, WriteY4mHeader) {
+  const std::string file_name =
+      test_utils::GetTestOutputFilePath(test_parameters_.file_name);
+  EXPECT_NE(
+      FileWriter::Open(file_name, FileWriter::kFileTypeY4m, &y4m_parameters_),
+      nullptr);
+  std::string y4m_header_string;
+  test_utils::GetTestData(test_parameters_.file_name, true, &y4m_header_string);
+  EXPECT_STREQ(y4m_header_string.c_str(),
+               test_parameters_.expected_header_string);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    WriteY4mHeader, FileWriterY4mHeaderTest,
+    testing::Values(
+        FileWriterY4mHeaderTestParameters(
+            "y4m_header_8bit", kChromaSamplePositionUnknown, kImageFormatYuv420,
+            /*bitdepth=*/8, kExpectedY4mHeader8bit),
+        FileWriterY4mHeaderTestParameters("y4m_header_10bit",
+                                          kChromaSamplePositionUnknown,
+                                          kImageFormatYuv420, /*bitdepth=*/10,
+                                          kExpectedY4mHeader10bit),
+        FileWriterY4mHeaderTestParameters("y4m_header_8bit_monochrome",
+                                          kChromaSamplePositionUnknown,
+                                          kImageFormatMonochrome400,
+                                          /*bitdepth=*/8,
+                                          kExpectedY4mHeader8bitMonochrome),
+        FileWriterY4mHeaderTestParameters("y4m_header_10bit_monochrome",
+                                          kChromaSamplePositionUnknown,
+                                          kImageFormatMonochrome400,
+                                          /*bitdepth=*/10,
+                                          kExpectedY4mHeader10bitMonochrome)));
+
+struct FileWriterTestParameters {
+  FileWriterTestParameters() = default;
+  FileWriterTestParameters(const FileWriterTestParameters&) = default;
+  FileWriterTestParameters& operator=(const FileWriterTestParameters&) =
+      default;
+  FileWriterTestParameters(FileWriterTestParameters&&) = default;
+  FileWriterTestParameters& operator=(FileWriterTestParameters&&) = default;
+  ~FileWriterTestParameters() = default;
+
+  FileWriterTestParameters(std::string file_name,
+                           FileWriter::FileType file_type,
+                           const FileWriter::Y4mParameters* y4m_parameters,
+                           size_t num_frames)
+      : file_name(std::move(file_name)),
+        file_type(file_type),
+        y4m_parameters(y4m_parameters),
+        num_frames(num_frames) {}
+  std::string file_name;
+  FileWriter::FileType file_type = FileWriter::kFileTypeRaw;
+  const FileWriter::Y4mParameters* y4m_parameters = nullptr;
+  size_t num_frames = 1;
+};
+
+std::ostream& operator<<(std::ostream& stream,
+                         const ChromaSamplePosition& position) {
+  switch (position) {
+    case kChromaSamplePositionUnknown:
+      stream << "kCromaSamplePositionUnknown";
+      break;
+    case kChromaSamplePositionVertical:
+      stream << "kChromaSamplePositionVertical";
+      break;
+    case kChromaSamplePositionColocated:
+      stream << "kChromaSamplePositionColocated";
+      break;
+    case kChromaSamplePositionReserved:
+      stream << "kChromaSamplePositionReserved";
+      break;
+  }
+  return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const ImageFormat& image_format) {
+  switch (image_format) {
+    case kImageFormatMonochrome400:
+      stream << "kImageFormatMonochrome400";
+      break;
+    case kImageFormatYuv420:
+      stream << "kImageFormatYuv420";
+      break;
+    case kImageFormatYuv422:
+      stream << "kImageFormatYuv422";
+      break;
+    case kImageFormatYuv444:
+      stream << "kImageFormatYuv444";
+      break;
+  }
+  return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const FileWriter::Y4mParameters& parameters) {
+  stream << "y4m_parameters:\n"
+         << "  width=" << parameters.width << "\n"
+         << "  height=" << parameters.height << "\n"
+         << "  frame_rate_numerator=" << parameters.frame_rate_numerator << "\n"
+         << "  frame_rate_denominator=" << parameters.frame_rate_denominator
+         << "\n"
+         << "  chroma_sample_position=" << parameters.chroma_sample_position
+         << "\n"
+         << "  image_format=" << parameters.image_format << "\n"
+         << "  bitdepth=" << parameters.bitdepth << "\n";
+
+  return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const FileWriterTestParameters& parameters) {
+  stream << "file_name=" << parameters.file_name << "\n"
+         << "file_type="
+         << (parameters.file_type == FileWriter::kFileTypeRaw ? "kFileTypeRaw"
+                                                              : "kFileTypeY4m")
+         << "\n";
+  if (parameters.y4m_parameters != nullptr) {
+    stream << *parameters.y4m_parameters;
+  } else {
+    stream << "y4m_parameters: <nullptr>\n";
+  }
+  stream << "num_frames=" << parameters.num_frames << "\n";
+  return stream;
+}
+
+class FileWriterTestBase
+    : public testing::TestWithParam<FileWriterTestParameters> {
+ public:
+  FileWriterTestBase() = default;
+  FileWriterTestBase(const FileWriterTestBase&) = delete;
+  FileWriterTestBase& operator=(const FileWriterTestBase&) = delete;
+  ~FileWriterTestBase() override = default;
+
+ protected:
+  void SetUp() override { OpenWriter(GetParam()); }
+
+  void OpenWriter(const FileWriterTestParameters& parameters) {
+    parameters_ = parameters;
+    parameters_.file_name = parameters.file_name;
+    file_writer_ = FileWriter::Open(
+        test_utils::GetTestOutputFilePath(parameters.file_name),
+        parameters_.file_type, parameters_.y4m_parameters);
+    ASSERT_NE(file_writer_, nullptr);
+  }
+
+  void WriteFramesAndCloseFile() {
+    if (parameters_.y4m_parameters != nullptr) {
+      image_format_ = parameters_.y4m_parameters->image_format;
+    }
+    decoder_buffer_ = GetFakeDecoderBuffer(image_format_);
+    for (size_t frame_num = 0; frame_num < parameters_.num_frames;
+         ++frame_num) {
+      ASSERT_TRUE(file_writer_->WriteFrame(*decoder_buffer_));
+    }
+    file_writer_ = nullptr;
+  }
+
+  ImageFormat image_format_ = kImageFormatYuv420;
+  FileWriterTestParameters parameters_;
+  std::unique_ptr<FileWriter> file_writer_;
+  std::unique_ptr<DecoderBuffer> decoder_buffer_;
+};
+
+class FileWriterTestRaw : public FileWriterTestBase {
+ public:
+  FileWriterTestRaw() = default;
+  FileWriterTestRaw(const FileWriterTestRaw&) = delete;
+  FileWriterTestRaw& operator=(const FileWriterTestRaw&) = delete;
+  ~FileWriterTestRaw() override = default;
+
+ protected:
+  void SetUp() override { FileWriterTestBase::SetUp(); }
+};
+
+class FileWriterTestY4m : public FileWriterTestBase {
+ public:
+  FileWriterTestY4m() = default;
+  FileWriterTestY4m(const FileWriterTestY4m&) = delete;
+  FileWriterTestY4m& operator=(const FileWriterTestY4m&) = delete;
+  ~FileWriterTestY4m() override = default;
+
+ protected:
+  void SetUp() override { FileWriterTestBase::SetUp(); }
+};
+
+TEST_P(FileWriterTestRaw, WriteRawFrames) {
+  WriteFramesAndCloseFile();
+
+  std::string actual_file_data;
+  test_utils::GetTestData(parameters_.file_name, true, &actual_file_data);
+
+  std::string expected_file_data;
+  for (size_t frame_num = 0; frame_num < parameters_.num_frames; ++frame_num) {
+    if (image_format_ == kImageFormatMonochrome400) {
+      expected_file_data += kExpectedRawDataMonochrome;
+    } else {
+      for (const auto& buffer : kExpectedRawData) {
+        expected_file_data += buffer;
+      }
+    }
+  }
+
+  ASSERT_EQ(actual_file_data, expected_file_data);
+}
+
+TEST_P(FileWriterTestY4m, WriteY4mFrames) {
+  WriteFramesAndCloseFile();
+
+  std::string actual_file_data;
+  test_utils::GetTestData(parameters_.file_name, true, &actual_file_data);
+
+  std::string expected_file_data;
+  for (size_t frame_num = 0; frame_num < parameters_.num_frames; ++frame_num) {
+    if (image_format_ == kImageFormatMonochrome400) {
+      const char* const* expected_data_planes =
+          (parameters_.y4m_parameters->bitdepth == 8)
+              ? kExpectedY4mFileData8bitMonochrome
+              : kExpectedY4mFileData10bitMonochrome;
+      // Skip the Y4M file header "plane" after frame 0.
+      for (size_t buffer_num = (frame_num == 0) ? 0 : 1;
+           buffer_num < kExpectedY4mDataBufferCountMonochrome; ++buffer_num) {
+        expected_file_data += expected_data_planes[buffer_num];
+      }
+    } else {
+      const char* const* expected_data_planes =
+          (parameters_.y4m_parameters->bitdepth == 8)
+              ? kExpectedY4mFileData8bit
+              : kExpectedY4mFileData10bit;
+
+      // Skip the Y4M file header "plane" after frame 0.
+      for (size_t buffer_num = (frame_num == 0) ? 0 : 1;
+           buffer_num < kExpectedY4mDataBufferCount; ++buffer_num) {
+        expected_file_data += expected_data_planes[buffer_num];
+      }
+    }
+  }
+
+  ASSERT_EQ(actual_file_data, expected_file_data);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    WriteRawFrames, FileWriterTestRaw,
+    testing::Values(
+        FileWriterTestParameters("raw_frames_test_1frame",
+                                 FileWriter::kFileTypeRaw,
+                                 /*y4m_parameters=*/nullptr,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("raw_frames_test_5frames",
+                                 FileWriter::kFileTypeRaw,
+                                 /*y4m_parameters=*/nullptr,
+                                 /*num_frames=*/5),
+        FileWriterTestParameters("raw_frames_test_1frame_monochrome",
+                                 FileWriter::kFileTypeRaw,
+                                 /*y4m_parameters=*/nullptr,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("raw_frames_test_5frames_monochrome",
+                                 FileWriter::kFileTypeRaw,
+                                 /*y4m_parameters=*/nullptr,
+                                 /*num_frames=*/5)));
+
+const FileWriter::Y4mParameters kY4mParameters8Bit = {
+    352,  // width
+    288,  // height
+    30,   // frame_rate_numerator
+    1,    // frame_rate_denominator
+    kChromaSamplePositionUnknown,
+    kImageFormatYuv420,
+    8  // bitdepth
+};
+
+const FileWriter::Y4mParameters kY4mParameters10Bit = {
+    352,  // width
+    288,  // height
+    30,   // frame_rate_numerator
+    1,    // frame_rate_denominator
+    kChromaSamplePositionUnknown,
+    kImageFormatYuv420,
+    10  // bitdepth
+};
+
+const FileWriter::Y4mParameters kY4mParameters8BitMonochrome = {
+    352,  // width
+    288,  // height
+    30,   // frame_rate_numerator
+    1,    // frame_rate_denominator
+    kChromaSamplePositionUnknown,
+    kImageFormatMonochrome400,
+    8  // bitdepth
+};
+
+const FileWriter::Y4mParameters kY4mParameters10BitMonochrome = {
+    352,  // width
+    288,  // height
+    30,   // frame_rate_numerator
+    1,    // frame_rate_denominator
+    kChromaSamplePositionUnknown,
+    kImageFormatMonochrome400,
+    10  // bitdepth
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    WriteY4mFrames, FileWriterTestY4m,
+    testing::Values(
+        FileWriterTestParameters("y4m_frames_test_8bit_1frame",
+                                 FileWriter::kFileTypeY4m, &kY4mParameters8Bit,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("y4m_frames_test_8bit_5frames",
+                                 FileWriter::kFileTypeY4m, &kY4mParameters8Bit,
+                                 /*num_frames=*/5),
+        FileWriterTestParameters("y4m_frames_test_10bit_1frame",
+                                 FileWriter::kFileTypeY4m, &kY4mParameters10Bit,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("y4m_frames_test_10bit_5frames",
+                                 FileWriter::kFileTypeY4m, &kY4mParameters10Bit,
+                                 /*num_frames=*/5),
+        FileWriterTestParameters("y4m_frames_test_8bit_1frame_monochrome",
+                                 FileWriter::kFileTypeY4m,
+                                 &kY4mParameters8BitMonochrome,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("y4m_frames_test_8bit_5frames_monochrome",
+                                 FileWriter::kFileTypeY4m,
+                                 &kY4mParameters8BitMonochrome,
+                                 /*num_frames=*/5),
+        FileWriterTestParameters("y4m_frames_test_10bit_1frame_monochrome",
+                                 FileWriter::kFileTypeY4m,
+                                 &kY4mParameters10BitMonochrome,
+                                 /*num_frames=*/1),
+        FileWriterTestParameters("y4m_frames_test_10bit_5frames_monochrome",
+                                 FileWriter::kFileTypeY4m,
+                                 &kY4mParameters10BitMonochrome,
+                                 /*num_frames=*/5)));
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/buffer_pool_test.cc b/src/buffer_pool_test.cc
new file mode 100644
index 0000000..abe681e
--- /dev/null
+++ b/src/buffer_pool_test.cc
@@ -0,0 +1,305 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/buffer_pool.h"
+
+#include <climits>
+#include <cstdint>
+#include <memory>
+#include <ostream>
+#include <tuple>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/frame_buffer_utils.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/gav1/frame_buffer.h"
+#include "src/internal_frame_buffer_list.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+#include "src/yuv_buffer.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(BufferPoolTest, RefCountedBufferPtr) {
+  InternalFrameBufferList buffer_list;
+  BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+                         GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+                         &buffer_list);
+  RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+  EXPECT_NE(buffer_ptr, nullptr);
+  EXPECT_EQ(buffer_ptr.use_count(), 1);
+
+  RefCountedBufferPtr buffer_ptr2 = buffer_ptr;
+  RefCountedBufferPtr buffer_ptr3 = buffer_ptr;
+  EXPECT_EQ(buffer_ptr.use_count(), 3);
+  EXPECT_EQ(buffer_ptr2.use_count(), 3);
+  EXPECT_EQ(buffer_ptr3.use_count(), 3);
+
+  buffer_ptr2 = nullptr;
+  EXPECT_EQ(buffer_ptr.use_count(), 2);
+  EXPECT_EQ(buffer_ptr2.use_count(), 0);
+  EXPECT_EQ(buffer_ptr3.use_count(), 2);
+
+  RefCountedBufferPtr buffer_ptr4 = std::move(buffer_ptr);
+  EXPECT_EQ(buffer_ptr.use_count(), 0);
+  EXPECT_EQ(buffer_ptr2.use_count(), 0);
+  EXPECT_EQ(buffer_ptr3.use_count(), 2);
+  EXPECT_EQ(buffer_ptr4.use_count(), 2);
+}
+
+TEST(RefCountedBufferTest, SetFrameDimensions) {
+  InternalFrameBufferList buffer_list;
+  BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+                         GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+                         &buffer_list);
+  RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+  EXPECT_NE(buffer_ptr, nullptr);
+
+  // Test the undocumented default values of rows4x4() and columns4x4(). (Not
+  // sure if this is a good idea.)
+  EXPECT_EQ(buffer_ptr->rows4x4(), 0);
+  EXPECT_EQ(buffer_ptr->columns4x4(), 0);
+
+  // Test the side effects of SetFrameDimensions().
+  ObuFrameHeader frame_header = {};
+  frame_header.rows4x4 = 20;
+  frame_header.columns4x4 = 30;
+  EXPECT_TRUE(buffer_ptr->SetFrameDimensions(frame_header));
+  EXPECT_EQ(buffer_ptr->rows4x4(), 20);
+  EXPECT_EQ(buffer_ptr->columns4x4(), 30);
+}
+
+TEST(RefCountedBuffertTest, WaitUntil) {
+  InternalFrameBufferList buffer_list;
+  BufferPool buffer_pool(OnInternalFrameBufferSizeChanged,
+                         GetInternalFrameBuffer, ReleaseInternalFrameBuffer,
+                         &buffer_list);
+  RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+  EXPECT_NE(buffer_ptr, nullptr);
+
+  int progress_row_cache;
+  buffer_ptr->SetProgress(10);
+  EXPECT_TRUE(buffer_ptr->WaitUntil(5, &progress_row_cache));
+  EXPECT_EQ(progress_row_cache, 10);
+
+  buffer_ptr->SetFrameState(kFrameStateDecoded);
+  EXPECT_TRUE(buffer_ptr->WaitUntil(500, &progress_row_cache));
+  EXPECT_EQ(progress_row_cache, INT_MAX);
+
+  buffer_ptr->Abort();
+  EXPECT_FALSE(buffer_ptr->WaitUntil(50, &progress_row_cache));
+}
+
+constexpr struct Params {
+  int width;
+  int height;
+  int8_t subsampling_x;
+  int8_t subsampling_y;
+  int border;
+} kParams[] = {
+    {1920, 1080, 1, 1, 96},   //
+    {1920, 1080, 1, 1, 64},   //
+    {1920, 1080, 1, 1, 32},   //
+    {1920, 1080, 1, 1, 160},  //
+    {1920, 1080, 1, 0, 160},  //
+    {1920, 1080, 0, 0, 160},  //
+};
+
+std::ostream& operator<<(std::ostream& os, const Params& param) {
+  return os << param.width << "x" << param.height
+            << ", subsampling(x/y): " << static_cast<int>(param.subsampling_x)
+            << "/" << static_cast<int>(param.subsampling_y)
+            << ", border: " << param.border;
+}
+
+class RefCountedBufferReallocTest
+    : public testing::TestWithParam<std::tuple<bool, Params>> {
+ protected:
+  const bool use_external_callbacks_ = std::get<0>(GetParam());
+  const Params& param_ = std::get<1>(GetParam());
+};
+
+TEST_P(RefCountedBufferReallocTest, 8Bit) {
+  InternalFrameBufferList buffer_list;
+  FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
+  GetFrameBufferCallback get_frame_buffer = nullptr;
+  ReleaseFrameBufferCallback release_frame_buffer = nullptr;
+  void* callback_private_data = nullptr;
+  if (use_external_callbacks_) {
+    on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
+    get_frame_buffer = GetInternalFrameBuffer;
+    release_frame_buffer = ReleaseInternalFrameBuffer;
+    callback_private_data = &buffer_list;
+  }
+
+  BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
+                         release_frame_buffer, callback_private_data);
+
+  RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+  EXPECT_NE(buffer_ptr, nullptr);
+
+  const Libgav1ImageFormat image_format = ComposeImageFormat(
+      /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
+  EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
+      /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
+      param_.border, param_.border, param_.border));
+
+  EXPECT_TRUE(buffer_ptr->Realloc(
+      /*bitdepth=*/8, /*is_monochrome=*/false, param_.width, param_.height,
+      param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
+      param_.border, param_.border));
+
+  // The first row of each plane is aligned at 16-byte boundaries.
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
+
+  // Subsequent rows are aligned at 16-byte boundaries.
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
+
+  // Check the borders.
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
+            param_.border >> param_.subsampling_y);
+
+  // Write to the upper-left corner of the border.
+  uint8_t* y_buffer = buffer_ptr->buffer()->data(kPlaneY);
+  int y_stride = buffer_ptr->buffer()->stride(kPlaneY);
+  y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
+           buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
+  // Write to the lower-right corner of the border.
+  uint8_t* v_buffer = buffer_ptr->buffer()->data(kPlaneV);
+  int v_stride = buffer_ptr->buffer()->stride(kPlaneV);
+  v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
+            buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
+               v_stride +
+           buffer_ptr->buffer()->width(kPlaneV) +
+           buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+TEST_P(RefCountedBufferReallocTest, 10Bit) {
+  InternalFrameBufferList buffer_list;
+  FrameBufferSizeChangedCallback on_frame_buffer_size_changed = nullptr;
+  GetFrameBufferCallback get_frame_buffer = nullptr;
+  ReleaseFrameBufferCallback release_frame_buffer = nullptr;
+  void* callback_private_data = nullptr;
+  if (use_external_callbacks_) {
+    on_frame_buffer_size_changed = OnInternalFrameBufferSizeChanged;
+    get_frame_buffer = GetInternalFrameBuffer;
+    release_frame_buffer = ReleaseInternalFrameBuffer;
+    callback_private_data = &buffer_list;
+  }
+
+  BufferPool buffer_pool(on_frame_buffer_size_changed, get_frame_buffer,
+                         release_frame_buffer, callback_private_data);
+
+  RefCountedBufferPtr buffer_ptr = buffer_pool.GetFreeBuffer();
+  EXPECT_NE(buffer_ptr, nullptr);
+
+  const Libgav1ImageFormat image_format = ComposeImageFormat(
+      /*is_monochrome=*/false, param_.subsampling_x, param_.subsampling_y);
+  EXPECT_TRUE(buffer_pool.OnFrameBufferSizeChanged(
+      /*bitdepth=*/8, image_format, param_.width, param_.height, param_.border,
+      param_.border, param_.border, param_.border));
+
+  EXPECT_TRUE(buffer_ptr->Realloc(
+      /*bitdepth=*/10, /*is_monochrome=*/false, param_.width, param_.height,
+      param_.subsampling_x, param_.subsampling_y, param_.border, param_.border,
+      param_.border, param_.border));
+
+  // The first row of each plane is aligned at 16-byte boundaries.
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneY)) % 16, 0);
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneU)) % 16, 0);
+  EXPECT_EQ(
+      reinterpret_cast<uintptr_t>(buffer_ptr->buffer()->data(kPlaneV)) % 16, 0);
+
+  // Subsequent rows are aligned at 16-byte boundaries.
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneY) % 16, 0);
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneU) % 16, 0);
+  EXPECT_EQ(buffer_ptr->buffer()->stride(kPlaneV) % 16, 0);
+
+  // Check the borders.
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneY), param_.border);
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneU),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneU),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneU),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneU),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->left_border(kPlaneV),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->right_border(kPlaneV),
+            param_.border >> param_.subsampling_x);
+  EXPECT_EQ(buffer_ptr->buffer()->top_border(kPlaneV),
+            param_.border >> param_.subsampling_y);
+  EXPECT_EQ(buffer_ptr->buffer()->bottom_border(kPlaneV),
+            param_.border >> param_.subsampling_y);
+
+  // Write to the upper-left corner of the border.
+  auto* y_buffer =
+      reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneY));
+  int y_stride = buffer_ptr->buffer()->stride(kPlaneY) / sizeof(uint16_t);
+  y_buffer[-buffer_ptr->buffer()->left_border(kPlaneY) -
+           buffer_ptr->buffer()->top_border(kPlaneY) * y_stride] = 0;
+  // Write to the lower-right corner of the border.
+  auto* v_buffer =
+      reinterpret_cast<uint16_t*>(buffer_ptr->buffer()->data(kPlaneV));
+  int v_stride = buffer_ptr->buffer()->stride(kPlaneV) / sizeof(uint16_t);
+  v_buffer[(buffer_ptr->buffer()->height(kPlaneV) +
+            buffer_ptr->buffer()->bottom_border(kPlaneV) - 1) *
+               v_stride +
+           buffer_ptr->buffer()->width(kPlaneV) +
+           buffer_ptr->buffer()->right_border(kPlaneV) - 1] = 0;
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+INSTANTIATE_TEST_SUITE_P(
+    Default, RefCountedBufferReallocTest,
+    testing::Combine(testing::Bool(),  // use_external_callbacks
+                     testing::ValuesIn(kParams)));
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/c_decoder_test.c b/src/c_decoder_test.c
new file mode 100644
index 0000000..9587262
--- /dev/null
+++ b/src/c_decoder_test.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2021 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __cplusplus
+#error Do not compile this file with a C++ compiler
+#endif
+
+// clang-format off
+#include "src/gav1/decoder.h"
+
+// Import the test frame #defines.
+#include "src/decoder_test_data.h"
+// clang-format on
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT_EQ(a, b)                                                      \
+  do {                                                                       \
+    if ((a) != (b)) {                                                        \
+      fprintf(stderr, "Assertion failure: (%s) == (%s), at %s:%d\n", #a, #b, \
+              __FILE__, __LINE__);                                           \
+      fprintf(stderr, "C DecoderTest failed\n");                             \
+      exit(1);                                                               \
+    }                                                                        \
+  } while (0)
+
+#define ASSERT_NE(a, b)                                                      \
+  do {                                                                       \
+    if ((a) == (b)) {                                                        \
+      fprintf(stderr, "Assertion failure: (%s) != (%s), at %s:%d\n", #a, #b, \
+              __FILE__, __LINE__);                                           \
+      fprintf(stderr, "C DecoderTest failed\n");                             \
+      exit(1);                                                               \
+    }                                                                        \
+  } while (0)
+
+#define ASSERT_TRUE(a)                                                   \
+  do {                                                                   \
+    if (!(a)) {                                                          \
+      fprintf(stderr, "Assertion failure: %s, at %s:%d\n", #a, __FILE__, \
+              __LINE__);                                                 \
+      fprintf(stderr, "C DecoderTest failed\n");                         \
+      exit(1);                                                           \
+    }                                                                    \
+  } while (0)
+
+#define ASSERT_FALSE(a)                                                     \
+  do {                                                                      \
+    if (a) {                                                                \
+      fprintf(stderr, "Assertion failure: !(%s), at %s:%d\n", #a, __FILE__, \
+              __LINE__);                                                    \
+      fprintf(stderr, "C DecoderTest failed\n");                            \
+      exit(1);                                                              \
+    }                                                                       \
+  } while (0)
+
+static const uint8_t kFrame1[] = {OBU_TEMPORAL_DELIMITER, OBU_SEQUENCE_HEADER,
+                                  OBU_FRAME_1};
+
+static const uint8_t kFrame2[] = {OBU_TEMPORAL_DELIMITER, OBU_FRAME_2};
+
+static const uint8_t kFrame1WithHdrCllAndHdrMdcv[] = {
+    OBU_TEMPORAL_DELIMITER, OBU_SEQUENCE_HEADER, OBU_METADATA_HDR_CLL,
+    OBU_METADATA_HDR_MDCV, OBU_FRAME_1};
+
+static const uint8_t kFrame2WithItutT35[] = {
+    OBU_TEMPORAL_DELIMITER, OBU_METADATA_ITUT_T35, OBU_FRAME_2};
+
+typedef struct DecoderTest {
+  Libgav1Decoder* decoder;
+  int frames_in_use;
+  void* buffer_private_data;
+  void* released_input_buffer;
+} DecoderTest;
+
+static void DecoderTestInit(DecoderTest* test) {
+  test->decoder = NULL;
+  test->frames_in_use = 0;
+  test->buffer_private_data = NULL;
+  test->released_input_buffer = NULL;
+}
+
+static void DecoderTestIncrementFramesInUse(DecoderTest* test) {
+  ++test->frames_in_use;
+}
+
+static void DecoderTestDecrementFramesInUse(DecoderTest* test) {
+  --test->frames_in_use;
+}
+
+static void DecoderTestSetReleasedInputBuffer(DecoderTest* test,
+                                              void* released_input_buffer) {
+  test->released_input_buffer = released_input_buffer;
+}
+
+static void DecoderTestSetBufferPrivateData(DecoderTest* test,
+                                            void* buffer_private_data) {
+  test->buffer_private_data = buffer_private_data;
+}
+
+typedef struct FrameBufferPrivate {
+  uint8_t* data[3];
+} FrameBufferPrivate;
+
+static Libgav1StatusCode GetFrameBuffer(
+    void* callback_private_data, int bitdepth, Libgav1ImageFormat image_format,
+    int width, int height, int left_border, int right_border, int top_border,
+    int bottom_border, int stride_alignment, Libgav1FrameBuffer* frame_buffer) {
+  Libgav1FrameBufferInfo info;
+  Libgav1StatusCode status = Libgav1ComputeFrameBufferInfo(
+      bitdepth, image_format, width, height, left_border, right_border,
+      top_border, bottom_border, stride_alignment, &info);
+  if (status != kLibgav1StatusOk) return status;
+
+  FrameBufferPrivate* buffer_private =
+      (FrameBufferPrivate*)malloc(sizeof(FrameBufferPrivate));
+  if (buffer_private == NULL) return kLibgav1StatusOutOfMemory;
+
+  for (int i = 0; i < 3; ++i) {
+    const size_t size = (i == 0) ? info.y_buffer_size : info.uv_buffer_size;
+    buffer_private->data[i] = (uint8_t*)malloc(sizeof(uint8_t) * size);
+    if (buffer_private->data[i] == NULL) {
+      for (int j = 0; j < i; j++) {
+        free(buffer_private->data[j]);
+      }
+      free(buffer_private);
+      return kLibgav1StatusOutOfMemory;
+    }
+  }
+
+  uint8_t* const y_buffer = buffer_private->data[0];
+  uint8_t* const u_buffer =
+      (info.uv_buffer_size != 0) ? buffer_private->data[1] : NULL;
+  uint8_t* const v_buffer =
+      (info.uv_buffer_size != 0) ? buffer_private->data[2] : NULL;
+
+  status = Libgav1SetFrameBuffer(&info, y_buffer, u_buffer, v_buffer,
+                                 buffer_private, frame_buffer);
+  if (status != kLibgav1StatusOk) return status;
+
+  DecoderTest* const decoder_test = (DecoderTest*)callback_private_data;
+  DecoderTestIncrementFramesInUse(decoder_test);
+  DecoderTestSetBufferPrivateData(decoder_test, frame_buffer->private_data);
+  return kLibgav1StatusOk;
+}
+
+static void ReleaseFrameBuffer(void* callback_private_data,
+                               void* buffer_private_data) {
+  FrameBufferPrivate* buffer_private = (FrameBufferPrivate*)buffer_private_data;
+  for (int i = 0; i < 3; ++i) {
+    free(buffer_private->data[i]);
+  }
+  free(buffer_private);
+  DecoderTest* const decoder_test = (DecoderTest*)callback_private_data;
+  DecoderTestDecrementFramesInUse(decoder_test);
+}
+
+static void ReleaseInputBuffer(void* private_data, void* input_buffer) {
+  DecoderTestSetReleasedInputBuffer((DecoderTest*)private_data, input_buffer);
+}
+
+static void DecoderTestSetUp(DecoderTest* test) {
+  Libgav1DecoderSettings settings;
+  Libgav1DecoderSettingsInitDefault(&settings);
+  settings.frame_parallel = 0;  // false
+  settings.get_frame_buffer = GetFrameBuffer;
+  settings.release_frame_buffer = ReleaseFrameBuffer;
+  settings.callback_private_data = test;
+  settings.release_input_buffer = ReleaseInputBuffer;
+  ASSERT_EQ(test->decoder, NULL);
+  ASSERT_EQ(Libgav1DecoderCreate(&settings, &test->decoder), kLibgav1StatusOk);
+  ASSERT_NE(test->decoder, NULL);
+}
+
+static void DecoderTestAPIFlowForNonFrameParallelMode(void) {
+  DecoderTest test;
+  DecoderTestInit(&test);
+  DecoderTestSetUp(&test);
+
+  Libgav1StatusCode status;
+  const Libgav1DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1, sizeof(kFrame1), 0,
+                                      (uint8_t*)&kFrame1);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  // In non-frame-parallel mode, decoding happens only in the DequeueFrame call.
+  // So there should be no frames in use yet.
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1);
+
+  // libgav1 has decoded frame1 and is holding a reference to it.
+  ASSERT_EQ(test.frames_in_use, 1);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2, sizeof(kFrame2), 0,
+                                      (uint8_t*)&kFrame2);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Dequeue the output of frame2.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame2);
+
+  ASSERT_EQ(test.frames_in_use, 2);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  // Signal end of stream (method 1). This should ensure that all the references
+  // are released.
+  status = Libgav1DecoderSignalEOS(test.decoder);
+
+  // libgav1 should have released all the reference frames now.
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Now, the decoder is ready to accept a new coded video sequence.
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1, sizeof(kFrame1), 0,
+                                      (uint8_t*)&kFrame1);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2, sizeof(kFrame2), 0,
+                                      (uint8_t*)&kFrame2);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Dequeue the output of frame2.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame2);
+
+  ASSERT_EQ(test.frames_in_use, 2);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  // Signal end of stream (method 2). This should ensure that all the references
+  // are released.
+  Libgav1DecoderDestroy(test.decoder);
+  test.decoder = NULL;
+
+  // libgav1 should have released all the frames now.
+  ASSERT_EQ(test.frames_in_use, 0);
+}
+
+static void
+DecoderTestNonFrameParallelModeEnqueueMultipleFramesWithoutDequeuing(void) {
+  DecoderTest test;
+  DecoderTestInit(&test);
+  DecoderTestSetUp(&test);
+
+  Libgav1StatusCode status;
+  const Libgav1DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1, sizeof(kFrame1), 0,
+                                      (uint8_t*)&kFrame1);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  // Until the output of frame1 is dequeued, no other frames can be enqueued.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2, sizeof(kFrame2), 0,
+                                      (uint8_t*)&kFrame2);
+  ASSERT_EQ(status, kLibgav1StatusTryAgain);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Delete the decoder instance.
+  Libgav1DecoderDestroy(test.decoder);
+  test.decoder = NULL;
+
+  ASSERT_EQ(test.frames_in_use, 0);
+}
+
+static void DecoderTestNonFrameParallelModeEOSBeforeDequeuingLastFrame(void) {
+  DecoderTest test;
+  DecoderTestInit(&test);
+  DecoderTestSetUp(&test);
+
+  Libgav1StatusCode status;
+  const Libgav1DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1, sizeof(kFrame1), 0,
+                                      (uint8_t*)&kFrame1);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1);
+
+  // Enqueue frame2 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2, sizeof(kFrame2), 0,
+                                      (uint8_t*)&kFrame2);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Signal end of stream before dequeuing the output of frame2.
+  status = Libgav1DecoderSignalEOS(test.decoder);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  // In this case, the output of the last frame that was enqueued is lost (which
+  // is intentional since end of stream was signaled without dequeueing it).
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  Libgav1DecoderDestroy(test.decoder);
+  test.decoder = NULL;
+}
+
+static void DecoderTestNonFrameParallelModeInvalidFrameAfterEOS(void) {
+  DecoderTest test;
+  DecoderTestInit(&test);
+  DecoderTestSetUp(&test);
+
+  Libgav1StatusCode status;
+  const Libgav1DecoderBuffer* buffer = NULL;
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1, sizeof(kFrame1), 0,
+                                      (uint8_t*)&kFrame1);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Signal end of stream.
+  status = Libgav1DecoderSignalEOS(test.decoder);
+
+  // libgav1 should have released all the reference frames now.
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Now, the decoder is ready to accept a new coded video sequence. But, we
+  // try to enqueue a frame that does not have a sequence header (which is not
+  // allowed).
+
+  // Enqueue frame2 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2, sizeof(kFrame2), 0,
+                                      (uint8_t*)&kFrame2);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame2 (this will fail since no sequence header has
+  // been seen since the last EOS signal).
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusBitstreamError);
+  ASSERT_EQ(test.released_input_buffer, &kFrame2);
+
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  Libgav1DecoderDestroy(test.decoder);
+  test.decoder = NULL;
+}
+
+static void DecoderTestMetadataObu(void) {
+  DecoderTest test;
+  DecoderTestInit(&test);
+  DecoderTestSetUp(&test);
+
+  Libgav1StatusCode status;
+  const Libgav1DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame1WithHdrCllAndHdrMdcv,
+                                      sizeof(kFrame1WithHdrCllAndHdrMdcv), 0,
+                                      (uint8_t*)&kFrame1WithHdrCllAndHdrMdcv);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  // Dequeue the output of frame1.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(buffer->has_hdr_cll, 1);
+  ASSERT_EQ(buffer->has_hdr_mdcv, 1);
+  ASSERT_EQ(buffer->has_itut_t35, 0);
+  ASSERT_EQ(test.released_input_buffer, &kFrame1WithHdrCllAndHdrMdcv);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status = Libgav1DecoderEnqueueFrame(test.decoder, kFrame2WithItutT35,
+                                      sizeof(kFrame2WithItutT35), 0,
+                                      (uint8_t*)&kFrame2WithItutT35);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+
+  ASSERT_EQ(test.frames_in_use, 1);
+
+  // Dequeue the output of frame2.
+  status = Libgav1DecoderDequeueFrame(test.decoder, &buffer);
+  ASSERT_EQ(status, kLibgav1StatusOk);
+  ASSERT_NE(buffer, NULL);
+  ASSERT_EQ(buffer->has_hdr_cll, 0);
+  ASSERT_EQ(buffer->has_hdr_mdcv, 0);
+  ASSERT_EQ(buffer->has_itut_t35, 1);
+  ASSERT_NE(buffer->itut_t35.payload_bytes, NULL);
+  ASSERT_NE(buffer->itut_t35.payload_size, 0);
+  ASSERT_EQ(test.released_input_buffer, &kFrame2WithItutT35);
+
+  ASSERT_EQ(test.frames_in_use, 2);
+  ASSERT_EQ(test.buffer_private_data, buffer->buffer_private_data);
+
+  status = Libgav1DecoderSignalEOS(test.decoder);
+  ASSERT_EQ(test.frames_in_use, 0);
+
+  Libgav1DecoderDestroy(test.decoder);
+}
+
+int main(void) {
+  fprintf(stderr, "C DecoderTest started\n");
+  DecoderTestAPIFlowForNonFrameParallelMode();
+  DecoderTestNonFrameParallelModeEnqueueMultipleFramesWithoutDequeuing();
+  DecoderTestNonFrameParallelModeEOSBeforeDequeuingLastFrame();
+  DecoderTestNonFrameParallelModeInvalidFrameAfterEOS();
+  DecoderTestMetadataObu();
+  fprintf(stderr, "C DecoderTest passed\n");
+  return 0;
+}
diff --git a/src/c_version_test.c b/src/c_version_test.c
new file mode 100644
index 0000000..e198ee7
--- /dev/null
+++ b/src/c_version_test.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2021 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __cplusplus
+#error Do not compile this file with a C++ compiler
+#endif
+
+// clang-format off
+#include "src/gav1/version.h"
+// clang-format on
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ASSERT_EQ(a, b)                                                      \
+  do {                                                                       \
+    if ((a) != (b)) {                                                        \
+      fprintf(stderr, "Assertion failure: (%s) == (%s), at %s:%d\n", #a, #b, \
+              __FILE__, __LINE__);                                           \
+      fprintf(stderr, "C VersionTest failed\n");                             \
+      exit(1);                                                               \
+    }                                                                        \
+  } while (0)
+
+#define ASSERT_NE(a, b)                                                      \
+  do {                                                                       \
+    if ((a) == (b)) {                                                        \
+      fprintf(stderr, "Assertion failure: (%s) != (%s), at %s:%d\n", #a, #b, \
+              __FILE__, __LINE__);                                           \
+      fprintf(stderr, "C VersionTest failed\n");                             \
+      exit(1);                                                               \
+    }                                                                        \
+  } while (0)
+
+#define ASSERT_TRUE(a)                                                   \
+  do {                                                                   \
+    if (!(a)) {                                                          \
+      fprintf(stderr, "Assertion failure: %s, at %s:%d\n", #a, __FILE__, \
+              __LINE__);                                                 \
+      fprintf(stderr, "C VersionTest failed\n");                         \
+      exit(1);                                                           \
+    }                                                                    \
+  } while (0)
+
+#define ASSERT_FALSE(a)                                                     \
+  do {                                                                      \
+    if (a) {                                                                \
+      fprintf(stderr, "Assertion failure: !(%s), at %s:%d\n", #a, __FILE__, \
+              __LINE__);                                                    \
+      fprintf(stderr, "C VersionTest failed\n");                            \
+      exit(1);                                                              \
+    }                                                                       \
+  } while (0)
+
+static void VersionTestGetVersion(void) {
+  const int library_version = Libgav1GetVersion();
+  ASSERT_EQ((library_version >> 24) & 0xff, 0);
+  // Note if we link against a shared object there's potential for a mismatch
+  // if a different library is loaded at runtime.
+  ASSERT_EQ((library_version >> 16) & 0xff, LIBGAV1_MAJOR_VERSION);
+  ASSERT_EQ((library_version >> 8) & 0xff, LIBGAV1_MINOR_VERSION);
+  ASSERT_EQ(library_version & 0xff, LIBGAV1_PATCH_VERSION);
+
+  const int header_version = LIBGAV1_VERSION;
+  ASSERT_EQ((header_version >> 24) & 0xff, 0);
+  ASSERT_EQ((header_version >> 16) & 0xff, LIBGAV1_MAJOR_VERSION);
+  ASSERT_EQ((header_version >> 8) & 0xff, LIBGAV1_MINOR_VERSION);
+  ASSERT_EQ(header_version & 0xff, LIBGAV1_PATCH_VERSION);
+}
+
+static void VersionTestGetVersionString(void) {
+  const char* version = Libgav1GetVersionString();
+  ASSERT_NE(version, NULL);
+}
+
+static void VersionTestGetBuildConfiguration(void) {
+  const char* config = Libgav1GetBuildConfiguration();
+  ASSERT_NE(config, NULL);
+}
+
+int main(void) {
+  fprintf(stderr, "C VersionTest started\n");
+  VersionTestGetVersion();
+  VersionTestGetVersionString();
+  VersionTestGetBuildConfiguration();
+  fprintf(stderr, "C VersionTest passed\n");
+  return 0;
+}
diff --git a/src/decoder_buffer_test.cc b/src/decoder_buffer_test.cc
new file mode 100644
index 0000000..b1d8bb8
--- /dev/null
+++ b/src/decoder_buffer_test.cc
@@ -0,0 +1,38 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/gav1/decoder_buffer.h"
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+// Tests the emulation of C++ enumerators by constexpr constants.
+TEST(DecoderBufferTest, EnumTest) {
+  ColorRange color_range = kLibgav1ColorRangeFull;
+
+  // Verify that we get the -Wswitch warning unless the switch statement
+  // handles both kColorRangeStudio and kColorRangeFull:
+  //   enumeration value 'kLibgav1ColorRangeFull' not handled in switch
+  switch (color_range) {
+    case kColorRangeStudio:
+      break;
+    case kColorRangeFull:
+      break;
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/decoder_test.cc b/src/decoder_test.cc
new file mode 100644
index 0000000..e274122
--- /dev/null
+++ b/src/decoder_test.cc
@@ -0,0 +1,379 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/gav1/decoder.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+
+#include "gtest/gtest.h"
+#include "src/decoder_test_data.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr uint8_t kFrame1[] = {OBU_TEMPORAL_DELIMITER, OBU_SEQUENCE_HEADER,
+                               OBU_FRAME_1};
+
+constexpr uint8_t kFrame2[] = {OBU_TEMPORAL_DELIMITER, OBU_FRAME_2};
+
+constexpr uint8_t kFrame1WithHdrCllAndHdrMdcv[] = {
+    OBU_TEMPORAL_DELIMITER, OBU_SEQUENCE_HEADER, OBU_METADATA_HDR_CLL,
+    OBU_METADATA_HDR_MDCV, OBU_FRAME_1};
+
+constexpr uint8_t kFrame2WithItutT35[] = {OBU_TEMPORAL_DELIMITER,
+                                          OBU_METADATA_ITUT_T35, OBU_FRAME_2};
+
+class DecoderTest : public testing::Test {
+ public:
+  void SetUp() override;
+  void IncrementFramesInUse() { ++frames_in_use_; }
+  void DecrementFramesInUse() { --frames_in_use_; }
+  void SetBufferPrivateData(void* buffer_private_data) {
+    buffer_private_data_ = buffer_private_data;
+  }
+  void SetReleasedInputBuffer(void* released_input_buffer) {
+    released_input_buffer_ = released_input_buffer;
+  }
+
+ protected:
+  std::unique_ptr<Decoder> decoder_;
+  int frames_in_use_ = 0;
+  void* buffer_private_data_ = nullptr;
+  void* released_input_buffer_ = nullptr;
+};
+
+struct FrameBufferPrivate {
+  uint8_t* data[3];
+};
+
+extern "C" {
+
+static Libgav1StatusCode GetFrameBuffer(
+    void* callback_private_data, int bitdepth, Libgav1ImageFormat image_format,
+    int width, int height, int left_border, int right_border, int top_border,
+    int bottom_border, int stride_alignment, Libgav1FrameBuffer* frame_buffer) {
+  Libgav1FrameBufferInfo info;
+  Libgav1StatusCode status = Libgav1ComputeFrameBufferInfo(
+      bitdepth, image_format, width, height, left_border, right_border,
+      top_border, bottom_border, stride_alignment, &info);
+  if (status != kLibgav1StatusOk) return status;
+
+  std::unique_ptr<FrameBufferPrivate> buffer_private(new (std::nothrow)
+                                                         FrameBufferPrivate);
+  if (buffer_private == nullptr) return kLibgav1StatusOutOfMemory;
+
+  for (int i = 0; i < 3; ++i) {
+    const size_t size = (i == 0) ? info.y_buffer_size : info.uv_buffer_size;
+    buffer_private->data[i] = new (std::nothrow) uint8_t[size];
+    if (buffer_private->data[i] == nullptr) {
+      return kLibgav1StatusOutOfMemory;
+    }
+  }
+
+  uint8_t* const y_buffer = buffer_private->data[0];
+  uint8_t* const u_buffer =
+      (info.uv_buffer_size != 0) ? buffer_private->data[1] : nullptr;
+  uint8_t* const v_buffer =
+      (info.uv_buffer_size != 0) ? buffer_private->data[2] : nullptr;
+
+  status = Libgav1SetFrameBuffer(&info, y_buffer, u_buffer, v_buffer,
+                                 buffer_private.release(), frame_buffer);
+  if (status != kLibgav1StatusOk) return status;
+
+  auto* const decoder_test = static_cast<DecoderTest*>(callback_private_data);
+  decoder_test->IncrementFramesInUse();
+  decoder_test->SetBufferPrivateData(frame_buffer->private_data);
+  return kLibgav1StatusOk;
+}
+
+static void ReleaseFrameBuffer(void* callback_private_data,
+                               void* buffer_private_data) {
+  auto* buffer_private = static_cast<FrameBufferPrivate*>(buffer_private_data);
+  for (auto& data : buffer_private->data) {
+    delete[] data;
+  }
+  delete buffer_private;
+  auto* const decoder_test = static_cast<DecoderTest*>(callback_private_data);
+  decoder_test->DecrementFramesInUse();
+}
+
+static void ReleaseInputBuffer(void* private_data, void* input_buffer) {
+  auto* const decoder_test = static_cast<DecoderTest*>(private_data);
+  decoder_test->SetReleasedInputBuffer(input_buffer);
+}
+
+}  // extern "C"
+
+void DecoderTest::SetUp() {
+  decoder_.reset(new (std::nothrow) Decoder());
+  ASSERT_NE(decoder_, nullptr);
+  DecoderSettings settings = {};
+  settings.frame_parallel = false;
+  settings.get_frame_buffer = GetFrameBuffer;
+  settings.release_frame_buffer = ReleaseFrameBuffer;
+  settings.callback_private_data = this;
+  settings.release_input_buffer = ReleaseInputBuffer;
+  ASSERT_EQ(decoder_->Init(&settings), kStatusOk);
+}
+
+TEST_F(DecoderTest, APIFlowForNonFrameParallelMode) {
+  StatusCode status;
+  const DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(kFrame1, sizeof(kFrame1), 0,
+                                  const_cast<uint8_t*>(kFrame1));
+  ASSERT_EQ(status, kStatusOk);
+
+  // In non-frame-parallel mode, decoding happens only in the DequeueFrame call.
+  // So there should be no frames in use yet.
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame1);
+
+  // libgav1 has decoded frame1 and is holding a reference to it.
+  EXPECT_EQ(frames_in_use_, 1);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status = decoder_->EnqueueFrame(kFrame2, sizeof(kFrame2), 0,
+                                  const_cast<uint8_t*>(kFrame2));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Dequeue the output of frame2.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame2);
+
+  EXPECT_EQ(frames_in_use_, 2);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  // Signal end of stream (method 1). This should ensure that all the references
+  // are released.
+  status = decoder_->SignalEOS();
+
+  // libgav1 should have released all the reference frames now.
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Now, the decoder is ready to accept a new coded video sequence.
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(kFrame1, sizeof(kFrame1), 0,
+                                  const_cast<uint8_t*>(kFrame1));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame1);
+
+  EXPECT_EQ(frames_in_use_, 1);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status = decoder_->EnqueueFrame(kFrame2, sizeof(kFrame2), 0,
+                                  const_cast<uint8_t*>(kFrame2));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Dequeue the output of frame2.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame2);
+
+  EXPECT_EQ(frames_in_use_, 2);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  // Signal end of stream (method 2). This should ensure that all the references
+  // are released.
+  decoder_ = nullptr;
+
+  // libgav1 should have released all the frames now.
+  EXPECT_EQ(frames_in_use_, 0);
+}
+
+TEST_F(DecoderTest, NonFrameParallelModeEnqueueMultipleFramesWithoutDequeuing) {
+  StatusCode status;
+  const DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(kFrame1, sizeof(kFrame1), 0,
+                                  const_cast<uint8_t*>(kFrame1));
+  ASSERT_EQ(status, kStatusOk);
+
+  // Until the output of frame1 is dequeued, no other frames can be enqueued.
+  status = decoder_->EnqueueFrame(kFrame2, sizeof(kFrame2), 0,
+                                  const_cast<uint8_t*>(kFrame2));
+  ASSERT_EQ(status, kStatusTryAgain);
+
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame1);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Delete the decoder instance.
+  decoder_ = nullptr;
+
+  EXPECT_EQ(frames_in_use_, 0);
+}
+
+TEST_F(DecoderTest, NonFrameParallelModeEOSBeforeDequeuingLastFrame) {
+  StatusCode status;
+  const DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(kFrame1, sizeof(kFrame1), 0,
+                                  const_cast<uint8_t*>(kFrame1));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame1);
+
+  // Enqueue frame2 for decoding.
+  status = decoder_->EnqueueFrame(kFrame2, sizeof(kFrame2), 0,
+                                  const_cast<uint8_t*>(kFrame2));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Signal end of stream before dequeuing the output of frame2.
+  status = decoder_->SignalEOS();
+  ASSERT_EQ(status, kStatusOk);
+
+  // In this case, the output of the last frame that was enqueued is lost (which
+  // is intentional since end of stream was signaled without dequeueing it).
+  EXPECT_EQ(frames_in_use_, 0);
+}
+
+TEST_F(DecoderTest, NonFrameParallelModeInvalidFrameAfterEOS) {
+  StatusCode status;
+  const DecoderBuffer* buffer = nullptr;
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(kFrame1, sizeof(kFrame1), 0,
+                                  const_cast<uint8_t*>(kFrame1));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(released_input_buffer_, &kFrame1);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Signal end of stream.
+  status = decoder_->SignalEOS();
+
+  // libgav1 should have released all the reference frames now.
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Now, the decoder is ready to accept a new coded video sequence. But, we
+  // try to enqueue a frame that does not have a sequence header (which is not
+  // allowed).
+
+  // Enqueue frame2 for decoding.
+  status = decoder_->EnqueueFrame(kFrame2, sizeof(kFrame2), 0,
+                                  const_cast<uint8_t*>(kFrame2));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 0);
+
+  // Dequeue the output of frame2 (this will fail since no sequence header has
+  // been seen since the last EOS signal).
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusBitstreamError);
+  EXPECT_EQ(released_input_buffer_, &kFrame2);
+
+  EXPECT_EQ(frames_in_use_, 0);
+}
+
+TEST_F(DecoderTest, MetadataObu) {
+  StatusCode status;
+  const DecoderBuffer* buffer;
+
+  // Enqueue frame1 for decoding.
+  status = decoder_->EnqueueFrame(
+      kFrame1WithHdrCllAndHdrMdcv, sizeof(kFrame1WithHdrCllAndHdrMdcv), 0,
+      const_cast<uint8_t*>(kFrame1WithHdrCllAndHdrMdcv));
+  ASSERT_EQ(status, kStatusOk);
+
+  // Dequeue the output of frame1.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(buffer->has_hdr_cll, 1);
+  EXPECT_EQ(buffer->has_hdr_mdcv, 1);
+  EXPECT_EQ(buffer->has_itut_t35, 0);
+  EXPECT_EQ(released_input_buffer_, &kFrame1WithHdrCllAndHdrMdcv);
+
+  // libgav1 has decoded frame1 and is holding a reference to it.
+  EXPECT_EQ(frames_in_use_, 1);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  // Enqueue frame2 for decoding.
+  status =
+      decoder_->EnqueueFrame(kFrame2WithItutT35, sizeof(kFrame2WithItutT35), 0,
+                             const_cast<uint8_t*>(kFrame2WithItutT35));
+  ASSERT_EQ(status, kStatusOk);
+
+  EXPECT_EQ(frames_in_use_, 1);
+
+  // Dequeue the output of frame2.
+  status = decoder_->DequeueFrame(&buffer);
+  ASSERT_EQ(status, kStatusOk);
+  ASSERT_NE(buffer, nullptr);
+  EXPECT_EQ(buffer->has_hdr_cll, 0);
+  EXPECT_EQ(buffer->has_hdr_mdcv, 0);
+  EXPECT_EQ(buffer->has_itut_t35, 1);
+  EXPECT_NE(buffer->itut_t35.payload_bytes, nullptr);
+  EXPECT_GT(buffer->itut_t35.payload_size, 0);
+  EXPECT_EQ(released_input_buffer_, &kFrame2WithItutT35);
+
+  EXPECT_EQ(frames_in_use_, 2);
+  EXPECT_EQ(buffer_private_data_, buffer->buffer_private_data);
+
+  status = decoder_->SignalEOS();
+  EXPECT_EQ(frames_in_use_, 0);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/decoder_test_data.h b/src/decoder_test_data.h
new file mode 100644
index 0000000..78b6b46
--- /dev/null
+++ b/src/decoder_test_data.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2022 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBGAV1_SRC_DECODER_TEST_DATA_H_
+#define LIBGAV1_SRC_DECODER_TEST_DATA_H_
+
+// The bytes for these two frames come from the libaom test vector
+// av1-1-b8-01-size-32x32.ivf
+#define OBU_TEMPORAL_DELIMITER 0x12, 0x0
+#define OBU_SEQUENCE_HEADER \
+  0xa, 0xa, 0x0, 0x0, 0x0, 0x2, 0x27, 0xfe, 0xff, 0xfc, 0xc0, 0x20
+#define OBU_FRAME_1                                                           \
+  0x32, 0x93, 0x2, 0x10, 0x0, 0xa8, 0x80, 0x0, 0x3, 0x0, 0x10, 0x10, 0x30,    \
+      0x0, 0xd3, 0xc6, 0xc6, 0x82, 0xaa, 0x5e, 0xbf, 0x82, 0xf2, 0xa4, 0xa4,  \
+      0x29, 0xab, 0xda, 0xd7, 0x1, 0x5, 0x0, 0xb3, 0xde, 0xa8, 0x6f, 0x8d,    \
+      0xbf, 0x1b, 0xa8, 0x25, 0xc3, 0x84, 0x7c, 0x1a, 0x2b, 0x8b, 0x0, 0xff,  \
+      0x19, 0x1f, 0x45, 0x7e, 0xe0, 0xbe, 0xe1, 0x3a, 0x63, 0xc2, 0xc6, 0x6e, \
+      0xf4, 0xc8, 0xce, 0x11, 0xe1, 0x9f, 0x48, 0x64, 0x72, 0xeb, 0xbb, 0x4f, \
+      0xf3, 0x94, 0xb4, 0xb6, 0x9d, 0x4f, 0x4, 0x18, 0x5e, 0x5e, 0x1b, 0x65,  \
+      0x49, 0x74, 0x90, 0x13, 0x50, 0xef, 0x8c, 0xb8, 0xe8, 0xd9, 0x8e, 0x9c, \
+      0xc9, 0x4d, 0xda, 0x60, 0x6a, 0xa, 0xf9, 0x75, 0xd0, 0x62, 0x69, 0xd,   \
+      0xf5, 0xdc, 0xa9, 0xb9, 0x4c, 0x8, 0x9e, 0x33, 0x15, 0xa3, 0xe1, 0x42,  \
+      0x0, 0xe2, 0xb0, 0x46, 0xd0, 0xf7, 0xad, 0x55, 0xbc, 0x75, 0xe9, 0xe3,  \
+      0x1f, 0xa3, 0x41, 0x11, 0xba, 0xaa, 0x81, 0xf3, 0xcb, 0x82, 0x87, 0x71, \
+      0x0, 0xe6, 0xb9, 0x8c, 0xe1, 0xe9, 0xd3, 0x21, 0xcc, 0xcd, 0xe7, 0x12,  \
+      0xb9, 0xe, 0x43, 0x6a, 0xa3, 0x76, 0x5c, 0x35, 0x90, 0x45, 0x36, 0x52,  \
+      0xb4, 0x2d, 0xa3, 0x55, 0xde, 0x20, 0xf8, 0x80, 0xe1, 0x26, 0x46, 0x1b, \
+      0x3f, 0x59, 0xc7, 0x2e, 0x5b, 0x4a, 0x73, 0xf8, 0xb3, 0xf4, 0x62, 0xf4, \
+      0xf5, 0xa4, 0xc2, 0xae, 0x9e, 0xa6, 0x9c, 0x10, 0xbb, 0xe1, 0xd6, 0x88, \
+      0x75, 0xb9, 0x85, 0x48, 0xe5, 0x7, 0x12, 0xf3, 0x11, 0x85, 0x8e, 0xa2,  \
+      0x95, 0x9d, 0xed, 0x50, 0xfb, 0x6, 0x5a, 0x1, 0x37, 0xc4, 0x8e, 0x9e,   \
+      0x73, 0x9b, 0x96, 0x64, 0xbd, 0x42, 0xb, 0x80, 0xde, 0x57, 0x86, 0xcb,  \
+      0x7d, 0xab, 0x12, 0xb2, 0xcc, 0xe6, 0xea, 0xb5, 0x89, 0xeb, 0x91, 0xb3, \
+      0x93, 0xb2, 0x4f, 0x2f, 0x5b, 0xf3, 0x72, 0x12, 0x51, 0x56, 0x75, 0xb3, \
+      0xdd, 0x49, 0xb6, 0x5b, 0x77, 0xbe, 0xc5, 0xd7, 0xd4, 0xaf, 0xd6, 0x6b, \
+      0x38
+#define OBU_FRAME_2                                                          \
+  0x32, 0x33, 0x30, 0x3, 0xc3, 0x0, 0xa7, 0x2e, 0x46, 0xa8, 0x80, 0x0, 0x3,  \
+      0x0, 0x10, 0x1, 0x0, 0xa0, 0x0, 0xed, 0xb1, 0x51, 0x15, 0x58, 0xc7,    \
+      0x69, 0x3, 0x26, 0x35, 0xeb, 0x5a, 0x2d, 0x7a, 0x53, 0x24, 0x26, 0x20, \
+      0xa6, 0x11, 0x7, 0x49, 0x76, 0xa3, 0xc7, 0x62, 0xf8, 0x3, 0x32, 0xb0,  \
+      0x98, 0x17, 0x3d, 0x80
+#define OBU_METADATA_HDR_CLL 0x2a, 0x06, 0x01, 0x27, 0x10, 0x0d, 0xdf, 0x80
+#define OBU_METADATA_HDR_MDCV                                                 \
+  0x2a, 0x1a, 0x02, 0xae, 0x14, 0x51, 0xec, 0x43, 0xd7, 0xb0, 0xa4, 0x26,     \
+      0x66, 0x0f, 0x5c, 0x50, 0x0d, 0x54, 0x39, 0x00, 0x0f, 0xa0, 0x00, 0x00, \
+      0x00, 0x00, 0x52, 0x80
+#define OBU_METADATA_ITUT_T35                                                  \
+  0x2a, 0xf, 0x04, 0xa6, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, \
+      0x00, 0x80, 0x00, 0x00
+
+#endif  // LIBGAV1_SRC_DECODER_TEST_DATA_H_
diff --git a/src/dsp/arm/common_neon_test.cc b/src/dsp/arm/common_neon_test.cc
new file mode 100644
index 0000000..03aed19
--- /dev/null
+++ b/src/dsp/arm/common_neon_test.cc
@@ -0,0 +1,208 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/arm/common_neon.h"
+
+#include "gtest/gtest.h"
+#include "src/utils/cpu.h"
+
+#if LIBGAV1_ENABLE_NEON
+#include <cstdint>
+
+#include "tests/block_utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockWidth = 16;
+constexpr int kMaxBlockHeight = 16;
+
+template <typename Pixel>
+class TransposeTest : public testing::Test {
+ public:
+  TransposeTest() {
+    for (int y = 0; y < kMaxBlockHeight; ++y) {
+      for (int x = 0; x < kMaxBlockWidth; ++x) {
+        src_block_[y][x] = y * 16 + x;
+        expected_transpose_[y][x] = x * 16 + y;
+      }
+    }
+  }
+
+  TransposeTest(const TransposeTest&) = delete;
+  TransposeTest& operator=(const TransposeTest&) = delete;
+  ~TransposeTest() override = default;
+
+ protected:
+  Pixel src_block_[kMaxBlockHeight][kMaxBlockWidth];
+  Pixel expected_transpose_[kMaxBlockHeight][kMaxBlockWidth];
+};
+
+using TransposeTestLowBitdepth = TransposeTest<uint8_t>;
+
+TEST_F(TransposeTestLowBitdepth, Transpose4x4Test) {
+  uint8x8_t a = Load4<1>(src_block_[1], Load4(src_block_[0]));
+  uint8x8_t b = Load4<1>(src_block_[3], Load4(src_block_[2]));
+  Transpose4x4(&a, &b);
+  uint8_t output_4x4[4][4];
+  StoreLo4(output_4x4[0], a);
+  StoreLo4(output_4x4[1], b);
+  StoreHi4(output_4x4[2], a);
+  StoreHi4(output_4x4[3], b);
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x4[0],
+                                        4, 4, kMaxBlockWidth, 4, false));
+}
+
+TEST_F(TransposeTestLowBitdepth, Transpose8x4Test) {
+  uint8x8_t a0 = Load4<1>(src_block_[4], Load4(src_block_[0]));
+  uint8x8_t a1 = Load4<1>(src_block_[5], Load4(src_block_[1]));
+  uint8x8_t a2 = Load4<1>(src_block_[6], Load4(src_block_[2]));
+  uint8x8_t a3 = Load4<1>(src_block_[7], Load4(src_block_[3]));
+  Transpose8x4(&a0, &a1, &a2, &a3);
+  uint8_t output_8x4[4][8];
+  vst1_u8(output_8x4[0], a0);
+  vst1_u8(output_8x4[1], a1);
+  vst1_u8(output_8x4[2], a2);
+  vst1_u8(output_8x4[3], a3);
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x4[0],
+                                        8, 4, kMaxBlockWidth, 8, false));
+}
+
+TEST_F(TransposeTestLowBitdepth, Transpose8x8Test) {
+  uint8x8_t input_8x8[8];
+  for (int i = 0; i < 8; ++i) {
+    input_8x8[i] = vld1_u8(src_block_[i]);
+  }
+  Transpose8x8(input_8x8);
+  uint8_t output_8x8[8][8];
+  for (int i = 0; i < 8; ++i) {
+    vst1_u8(output_8x8[i], input_8x8[i]);
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
+                                        8, 8, kMaxBlockWidth, 8, false));
+}
+
+TEST_F(TransposeTestLowBitdepth, Transpose8x16Test) {
+  uint8x16_t input_8x16[8];
+  for (int i = 0; i < 8; ++i) {
+    input_8x16[i] =
+        vcombine_u8(vld1_u8(src_block_[i]), vld1_u8(src_block_[i + 8]));
+  }
+  Transpose8x16(input_8x16);
+  uint8_t output_16x8[8][16];
+  for (int i = 0; i < 8; ++i) {
+    vst1q_u8(output_16x8[i], input_8x16[i]);
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_16x8[0],
+                                        16, 8, kMaxBlockWidth, 16, false));
+}
+
+using TransposeTestHighBitdepth = TransposeTest<uint16_t>;
+
+TEST_F(TransposeTestHighBitdepth, Transpose4x4Test) {
+  uint16x4_t input_4x4[4];
+  input_4x4[0] = vld1_u16(src_block_[0]);
+  input_4x4[1] = vld1_u16(src_block_[1]);
+  input_4x4[2] = vld1_u16(src_block_[2]);
+  input_4x4[3] = vld1_u16(src_block_[3]);
+  Transpose4x4(input_4x4);
+  uint16_t output_4x4[4][4];
+  for (int i = 0; i < 4; ++i) {
+    vst1_u16(output_4x4[i], input_4x4[i]);
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x4[0],
+                                        4, 4, kMaxBlockWidth, 4, false));
+}
+
+TEST_F(TransposeTestHighBitdepth, Transpose4x8Test) {
+  uint16x8_t input_4x8[4];
+  for (int i = 0; i < 4; ++i) {
+    input_4x8[i] = vld1q_u16(src_block_[i]);
+  }
+  Transpose4x8(input_4x8);
+  uint16_t output_4x8[4][8];
+  for (int i = 0; i < 4; ++i) {
+    vst1q_u16(output_4x8[i], input_4x8[i]);
+    memcpy(&expected_transpose_[i][4], &expected_transpose_[i + 4][0],
+           4 * sizeof(expected_transpose_[0][0]));
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_4x8[0],
+                                        8, 4, kMaxBlockWidth, 8, false));
+}
+
+TEST_F(TransposeTestHighBitdepth, LoopFilterTranspose4x8Test) {
+  uint16x8_t input_4x8[4];
+  for (int i = 0; i < 4; ++i) {
+    input_4x8[i] = vld1q_u16(src_block_[i]);
+  }
+  LoopFilterTranspose4x8(input_4x8);
+  uint16_t output_4x8[4][8];
+  for (int i = 0; i < 4; ++i) {
+    vst1q_u16(output_4x8[i], input_4x8[i]);
+  }
+  // a[0]: 03 13 23 33 04 14 24 34  p0q0
+  // a[1]: 02 12 22 32 05 15 25 35  p1q1
+  // a[2]: 01 11 21 31 06 16 26 36  p2q2
+  // a[3]: 00 10 20 30 07 17 27 37  p3q3
+  static constexpr uint16_t expected_output[4][8] = {
+      {0x03, 0x13, 0x23, 0x33, 0x04, 0x14, 0x24, 0x34},
+      {0x02, 0x12, 0x22, 0x32, 0x05, 0x15, 0x25, 0x35},
+      {0x01, 0x11, 0x21, 0x31, 0x06, 0x16, 0x26, 0x36},
+      {0x00, 0x10, 0x20, 0x30, 0x07, 0x17, 0x27, 0x37},
+  };
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_output[0], output_4x8[0], 8, 4,
+                                        8, 8, false));
+}
+
+TEST_F(TransposeTestHighBitdepth, Transpose8x8Test) {
+  uint16x8_t input_8x8[8];
+  for (int i = 0; i < 8; ++i) {
+    input_8x8[i] = vld1q_u16(src_block_[i]);
+  }
+  Transpose8x8(input_8x8);
+  uint16_t output_8x8[8][8];
+  for (int i = 0; i < 8; ++i) {
+    vst1q_u16(output_8x8[i], input_8x8[i]);
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
+                                        8, 8, kMaxBlockWidth, 8, false));
+}
+
+TEST_F(TransposeTestHighBitdepth, Transpose8x8SignedTest) {
+  int16x8_t input_8x8[8];
+  for (int i = 0; i < 8; ++i) {
+    input_8x8[i] = vreinterpretq_s16_u16(vld1q_u16(src_block_[i]));
+  }
+  Transpose8x8(input_8x8);
+  uint16_t output_8x8[8][8];
+  for (int i = 0; i < 8; ++i) {
+    vst1q_u16(output_8x8[i], vreinterpretq_u16_s16(input_8x8[i]));
+  }
+  EXPECT_TRUE(test_utils::CompareBlocks(expected_transpose_[0], output_8x8[0],
+                                        8, 8, kMaxBlockWidth, 8, false));
+}
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
+
+#else  // !LIBGAV1_ENABLE_NEON
+
+TEST(CommonDspTest, NEON) {
+  GTEST_SKIP()
+      << "Build this module for Arm with NEON enabled to enable the tests.";
+}
+
+#endif  // LIBGAV1_ENABLE_NEON
diff --git a/src/dsp/average_blend_test.cc b/src/dsp/average_blend_test.cc
new file mode 100644
index 0000000..6d1100a
--- /dev/null
+++ b/src/dsp/average_blend_test.cc
@@ -0,0 +1,347 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/average_blend.h"
+
+#include <cassert>
+#include <cstdint>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/distance_weighted_blend.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kNumSpeedTests = 5e8;
+constexpr char kAverageBlend[] = "AverageBlend";
+// average_blend is applied to compound prediction values. This implies a range
+// far exceeding that of pixel values.
+// The ranges include kCompoundOffset in 10bpp and 12bpp.
+// see: src/dsp/convolve.cc & src/dsp/warp.cc.
+constexpr int kCompoundPredictionRange[3][2] = {
+    // 8bpp
+    {-5132, 9212},
+    // 10bpp
+    {3988, 61532},
+    // 12bpp
+    {3974, 61559},
+};
+
+template <int bitdepth, typename Pixel>
+class AverageBlendTest : public testing::TestWithParam<BlockSize>,
+                         public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  AverageBlendTest() = default;
+  ~AverageBlendTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    AverageBlendInit_C();
+    DistanceWeightedBlendInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_func_ = dsp->average_blend;
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        AverageBlendInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      AverageBlendInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    func_ = dsp->average_blend;
+    dist_blend_func_ = dsp->distance_weighted_blend;
+  }
+
+ protected:
+  void Test(const char* digest, int num_tests, bool debug);
+
+ private:
+  using PredType =
+      typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
+  static constexpr int kDestStride = kMaxSuperBlockSizeInPixels;
+  const int width_ = kBlockWidthPixels[GetParam()];
+  const int height_ = kBlockHeightPixels[GetParam()];
+  alignas(kMaxAlignment) PredType
+      source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
+  alignas(kMaxAlignment) PredType
+      source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
+  Pixel dest_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
+  Pixel reference_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] =
+      {};
+  dsp::AverageBlendFunc base_func_;
+  dsp::AverageBlendFunc func_;
+  dsp::DistanceWeightedBlendFunc dist_blend_func_;
+};
+
+template <int bitdepth, typename Pixel>
+void AverageBlendTest<bitdepth, Pixel>::Test(const char* digest, int num_tests,
+                                             bool debug) {
+  if (func_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  PredType* src_1 = source1_;
+  PredType* src_2 = source2_;
+  for (int y = 0; y < height_; ++y) {
+    for (int x = 0; x < width_; ++x) {
+      constexpr int bitdepth_index = (bitdepth - 8) >> 1;
+      const int min_val = kCompoundPredictionRange[bitdepth_index][0];
+      const int max_val = kCompoundPredictionRange[bitdepth_index][1];
+      src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+      src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+    }
+    src_1 += width_;
+    src_2 += width_;
+  }
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_tests; ++i) {
+    const absl::Time start = absl::Now();
+    func_(source1_, source2_, width_, height_, dest_,
+          sizeof(dest_[0]) * kDestStride);
+    elapsed_time += absl::Now() - start;
+  }
+  if (debug) {
+    if (base_func_ != nullptr) {
+      base_func_(source1_, source2_, width_, height_, reference_,
+                 sizeof(reference_[0]) * kDestStride);
+    } else {
+      // Use dist_blend_func_ as the base for C tests.
+      const int8_t weight = 8;
+      dist_blend_func_(source1_, source2_, weight, weight, width_, height_,
+                       reference_, sizeof(reference_[0]) * kDestStride);
+    }
+    EXPECT_TRUE(test_utils::CompareBlocks(dest_, reference_, width_, height_,
+                                          kDestStride, kDestStride, false));
+  }
+
+  test_utils::CheckMd5Digest(kAverageBlend, ToString(GetParam()), digest, dest_,
+                             sizeof(dest_[0]) * kDestStride * height_,
+                             elapsed_time);
+}
+
+const BlockSize kTestParam[] = {
+    kBlock4x4,    kBlock4x8,     kBlock4x16,  kBlock8x4,   kBlock8x8,
+    kBlock8x16,   kBlock8x32,    kBlock16x4,  kBlock16x8,  kBlock16x16,
+    kBlock16x32,  kBlock16x64,   kBlock32x8,  kBlock32x16, kBlock32x32,
+    kBlock32x64,  kBlock64x16,   kBlock64x32, kBlock64x64, kBlock64x128,
+    kBlock128x64, kBlock128x128,
+};
+
+using AverageBlendTest8bpp = AverageBlendTest<8, uint8_t>;
+
+const char* GetAverageBlendDigest8bpp(const BlockSize block_size) {
+  static const char* const kDigests[kMaxBlockSizes] = {
+      // 4xN
+      "152bcc35946900b1ed16369b3e7a81b7",
+      "c23e9b5698f7384eaae30a3908118b77",
+      "f2da31d940f62490c368c03d32d3ede8",
+      // 8xN
+      "73c95485ef956e1d9ab914e88e6a202b",
+      "d90d3abd368e58c513070a88b34649ba",
+      "77f7d53d0edeffb3537afffd9ff33a4a",
+      "460b9b1e6b83f65f013cfcaf67ec0122",
+      // 16xN
+      "96454a56de940174ff92e9bb686d6d38",
+      "a50e268e93b48ae39cc2a47d377410e2",
+      "65c8502ff6d78065d466f9911ed6bb3e",
+      "bc2c873b9f5d74b396e1df705e87f699",
+      "b4dae656484b2d255d1e09b7f34e12c1",
+      // 32xN
+      "7e1e5db92b22a96e5226a23de883d766",
+      "ca40d46d89773e7f858b15fcecd43cc0",
+      "bfdc894707323f4dc43d1326309f8368",
+      "f4733417621719b7feba3166ec0da5b9",
+      // 64xN
+      "378fa0594d22f01c8e8931c2a908d7c4",
+      "db38fe2e082bd4a09acb3bb1d52ee11e",
+      "3ad44401cc731215c46c9b7d96f7e4ae",
+      "6c43267be5ed03d204a05fe36090f870",
+      // 128xN
+      "c8cfe46ebf166c1cbf08e8804206aadb",
+      "b0557b5156d2334c8ce4a7ee12f9d6b4",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+TEST_P(AverageBlendTest8bpp, Blending) {
+  Test(GetAverageBlendDigest8bpp(GetParam()), 1, false);
+}
+
+TEST_P(AverageBlendTest8bpp, DISABLED_Speed) {
+  Test(GetAverageBlendDigest8bpp(GetParam()),
+       kNumSpeedTests /
+           (kBlockHeightPixels[GetParam()] * kBlockWidthPixels[GetParam()]),
+       false);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, AverageBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, AverageBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using AverageBlendTest10bpp = AverageBlendTest<10, uint16_t>;
+
+const char* GetAverageBlendDigest10bpp(const BlockSize block_size) {
+  static const char* const kDigests[kMaxBlockSizes] = {
+      // 4xN
+      "98c0671c092b4288adcaaa17362cc4a3",
+      "7083f3def8bfb63ab3a985ef5616a923",
+      "a7211ee2eaa6f88e08875b377d17b0f1",
+      // 8xN
+      "11f9ab881700f2ef0f82d8d4662868c6",
+      "3bee144b9ea6f4288b860c24f88a22f3",
+      "27113bd17bf95034f100e9046c7b59d2",
+      "c42886a5e16e23a81e43833d34467558",
+      // 16xN
+      "b0ac2eb0a7a6596d6d1339074c7f8771",
+      "24c9e079b9a8647a6ee03f5441f2cdd9",
+      "dd05777751ccdb4356856c90e1176e53",
+      "27b1d69d035b1525c013b7373cfe3875",
+      "08c46403afe19e6b008ccc8f56633da9",
+      // 32xN
+      "36d434db11298aba76166df06e9b8125",
+      "efd24dd7b555786bff1a482e51170ea3",
+      "3b37ddac87de443cd18784f02c2d1dd5",
+      "80d8070939a743a20689a65bf5dc0a68",
+      // 64xN
+      "88e747246237c6408d0bd4cc3ecc8396",
+      "af1fe8c52487c9f2951c3ea516828abb",
+      "ea6f18ff56b053748c18032b7e048e83",
+      "af0cb87fe27d24c2e0afd2c90a8533a6",
+      // 128xN
+      "16a83b19911d6dc7278a694b8baa9901",
+      "bd22e77ce6fa727267ff63eeb4dcb19c",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+TEST_P(AverageBlendTest10bpp, Blending) {
+  Test(GetAverageBlendDigest10bpp(GetParam()), 1, false);
+}
+
+TEST_P(AverageBlendTest10bpp, DISABLED_Speed) {
+  Test(GetAverageBlendDigest10bpp(GetParam()),
+       kNumSpeedTests /
+           (kBlockHeightPixels[GetParam()] * kBlockHeightPixels[GetParam()]) /
+           2,
+       false);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, AverageBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, AverageBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using AverageBlendTest12bpp = AverageBlendTest<12, uint16_t>;
+
+const char* GetAverageBlendDigest12bpp(const BlockSize block_size) {
+  static const char* const kDigests[kMaxBlockSizes] = {
+      // 4xN
+      "8f5ad8fba61a0f1cb6b77f5460c241be",
+      "3a9d017848fdb4162315c689b4449ac6",
+      "bb97029fff021b168b98b209dcee5123",
+      // 8xN
+      "a7ff1b199965b8856499ae3f1b2c48eb",
+      "05220c72835fc4662d261183df0a57cf",
+      "97de8c325f1475c44e1afc44183e55ad",
+      "60d820c46cad14d9d934da238bb79707",
+      // 16xN
+      "f3e4863121819bc28f7c1f453898650c",
+      "5f5f68d21269d7df546c848921e8f2cd",
+      "17efe0b0fce1f8d4c7bc6eacf769063e",
+      "3da591e201f44511cdd6c465692ace1e",
+      "5a0ca6c88664d2e918a032b5fcf66070",
+      // 32xN
+      "efe236bee8a9fef90b99d8012006f985",
+      "d6ff3aacbbbadff6d0ccb0873fb9fa2a",
+      "38801f7361052873423d57b574aabddc",
+      "55c76772ecdc1721e92ca04d2fc7c089",
+      // 64xN
+      "4261ecdde34eedc4e5066a93e0f64881",
+      "fe82e012efab872672193316d670fd82",
+      "6c698bc2d4acf4444a64ac55ae9641de",
+      "98626e25101cff69019d1b7e6e439404",
+      // 128xN
+      "fe0f3c89dd39786df1c952a2470d680d",
+      "af7e166fc3d8c9ce85789acf3467ed9d",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+TEST_P(AverageBlendTest12bpp, Blending) {
+  Test(GetAverageBlendDigest12bpp(GetParam()), 1, false);
+}
+
+TEST_P(AverageBlendTest12bpp, DISABLED_Speed) {
+  Test(GetAverageBlendDigest12bpp(GetParam()),
+       kNumSpeedTests /
+           (kBlockHeightPixels[GetParam()] * kBlockHeightPixels[GetParam()]) /
+           2,
+       false);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, AverageBlendTest12bpp,
+                         testing::ValuesIn(kTestParam));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const BlockSize param) {
+  return os << ToString(param);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/cdef_test.cc b/src/dsp/cdef_test.cc
new file mode 100644
index 0000000..c25d7df
--- /dev/null
+++ b/src/dsp/cdef_test.cc
@@ -0,0 +1,453 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/cdef.h"
+
+#include <cstdint>
+#include <cstring>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/third_party/libvpx/md5_helper.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr char kCdef[] = "Cdef";
+constexpr char kCdefDirectionName[] = "Cdef Direction";
+constexpr char kCdefFilterName[] = "Cdef Filtering";
+constexpr int kTestBufferStride = 8;
+constexpr int kTestBufferSize = 64;
+constexpr int kSourceStride = kMaxSuperBlockSizeInPixels + 2 * 8;
+constexpr int kSourceBufferSize =
+    (kMaxSuperBlockSizeInPixels + 2 * 3) * kSourceStride;
+constexpr int kNumSpeedTests = 5000;
+
+const char* GetDirectionDigest(const int bitdepth, const int num_runs) {
+  static const char* const kDigest[3][2] = {
+      {"de78c820a1fec7e81385aa0a615dbf8c", "7bfc543244f932a542691480dc4541b2"},
+      {"b54236de5d25e16c0f8678d9784cb85e", "559144cf183f3c69cb0e5d98cbf532ff"},
+      {"5532919a157c4f937da9e822bdb105f7", "dd9dfca6dfca83777d942e693c17627a"}};
+  const int bitdepth_index = (bitdepth - 8) / 2;
+  const int run_index = (num_runs == 1) ? 0 : 1;
+  return kDigest[bitdepth_index][run_index];
+}
+
+// The 'int' parameter is unused but required to allow for instantiations of C,
+// NEON, etc.
+template <int bitdepth, typename Pixel>
+class CdefDirectionTest : public testing::TestWithParam<int> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  CdefDirectionTest() = default;
+  CdefDirectionTest(const CdefDirectionTest&) = delete;
+  CdefDirectionTest& operator=(const CdefDirectionTest&) = delete;
+  ~CdefDirectionTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    CdefInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_cdef_direction_ = nullptr;
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      CdefInit_SSE4_1();
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        CdefInit_AVX2();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      CdefInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    cur_cdef_direction_ = dsp->cdef_direction;
+  }
+
+  void TestRandomValues(int num_runs);
+
+  Pixel buffer_[kTestBufferSize];
+  int strength_;
+  int size_;
+
+  CdefDirectionFunc base_cdef_direction_;
+  CdefDirectionFunc cur_cdef_direction_;
+};
+
+template <int bitdepth, typename Pixel>
+void CdefDirectionTest<bitdepth, Pixel>::TestRandomValues(int num_runs) {
+  if (cur_cdef_direction_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  absl::Duration elapsed_time;
+  libvpx_test::MD5 actual_digest;
+  for (int num_tests = 0; num_tests < num_runs; ++num_tests) {
+    for (int level = 0; level < (1 << bitdepth); level += 1 + (bitdepth - 8)) {
+      for (int bits = 0; bits <= bitdepth; ++bits) {
+        for (auto& pixel : buffer_) {
+          pixel = Clip3((rnd.Rand16() & ((1 << bits) - 1)) + level, 0,
+                        (1 << bitdepth) - 1);
+        }
+        int output[2] = {};
+        const absl::Time start = absl::Now();
+        cur_cdef_direction_(buffer_, kTestBufferStride * sizeof(Pixel),
+                            reinterpret_cast<uint8_t*>(&output[0]), &output[1]);
+        elapsed_time += absl::Now() - start;
+        actual_digest.Add(reinterpret_cast<const uint8_t*>(output),
+                          sizeof(output));
+      }
+    }
+  }
+  test_utils::CheckMd5Digest(kCdef, kCdefDirectionName,
+                             GetDirectionDigest(bitdepth, num_runs),
+                             actual_digest.Get(), elapsed_time);
+}
+
+using CdefDirectionTest8bpp = CdefDirectionTest<8, uint8_t>;
+
+TEST_P(CdefDirectionTest8bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefDirectionTest8bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests / 100);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefDirectionTest8bpp, testing::Values(0));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CdefDirectionTest8bpp, testing::Values(0));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, CdefDirectionTest8bpp, testing::Values(0));
+#endif
+
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, CdefDirectionTest8bpp, testing::Values(0));
+#endif  // LIBGAV1_ENABLE_AVX2
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using CdefDirectionTest10bpp = CdefDirectionTest<10, uint16_t>;
+
+TEST_P(CdefDirectionTest10bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefDirectionTest10bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests / 100);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefDirectionTest10bpp, testing::Values(0));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CdefDirectionTest10bpp, testing::Values(0));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using CdefDirectionTest12bpp = CdefDirectionTest<12, uint16_t>;
+
+TEST_P(CdefDirectionTest12bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefDirectionTest12bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests / 100);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefDirectionTest12bpp, testing::Values(0));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigest[] = {
+      "b6fe1a1f5bbb23e35197160ce57d90bd", "8aed39871b19184f1d381b145779bc33",
+      "82653dd66072e8ebd967083a0413ab03", "421c048396bc66ffaa6aafa016c7bc54",
+      "1f70ba51091e8c6034c3f0974af241c3", "8f700997452a24091136ca58890a5be4",
+      "9e3dea21ee4246172121f0420eccd899", "0848bdeffa74145758ef47992e1035c4",
+      "0bb55818de986e9d988b0c1cc6883887", "9b558a7eefc934f90cd09ca26b998bfd",
+      "3a38670f8c5f0c61cc47c9c79da728d2", "ed18fe91180e78008ccb98e9019bed69",
+      "2aa4bbcb6fb088ad42bde76be014dff0", "88f746f0d6c079ab8e9ecc7ff67524c7",
+      "7cffa948f5ddbccc7c6b07d15ca9eb69", "5e22c1c89735965dda935d1249129548",
+      "e765133d133b94e1578c8c5616248a96", "da95d47cad74eb4a075893ca98e658ab",
+  };
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigest[] = {
+      "0a9630b39974850998db653b07e09ab4", "97a924661d931b23ee57893da617ae70",
+      "0d79516b9a491ce5112eb00bbae5eb80", "d5801fd96029a7509cf66dde61e8e2d8",
+      "5bf5c0ea5a85e9b6c1e6991619c34ebc", "e2f1c08a8b3cd93b3a85511493a0ee31",
+      "45c047d2be5e2dcf6094937780a3f88a", "346caf437c1ad85862de72a622e29845",
+      "0e9cb69d24d9badbe956da779d912b05", "81803dcb00971237b3fe6372564a842f",
+      "17681ad2ed4a2456d70760852af6c6fd", "5312f8049a08a5f9b1708fda936f7a55",
+      "3f0f522f3a33e4ff2a97bdc1e614c5c4", "3818a50be7fe16aa0c636a7392d1eceb",
+      "c6849b8cd77a076dc7e3c26e8cd55b9e", "223c0dd685bbc74aec1d088356708433",
+      "90992957cb8103222aa2fb43c6cd2fc4", "a4ba6edcefe4130851c4c2607b147f95",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigest[] = {
+      "a32569989c42fd4254979f70c1c65f5a", "dc389048217633e2dd64126376be7d25",
+      "3b0e8dae294895330f349863b1773c39", "9741fe8d27d109cb99b7a9cdc030f52a",
+      "ab70f3729b52287c6432ba7624280a68", "c1e5cf39cbc8030b82e09633c6c67d42",
+      "d5120a196164ff5a0ad7aa8c02e9b064", "1133759f3aee3a362a0ab668f6faf843",
+      "feb0ab7f515665f79fce213e8cd2fb10", "e86ea55c2d6d5cc69716535bd455c99f",
+      "e463da1b9d089b6ee82c041794257fd7", "27800e4af0cceeaf0a95c96275a7befe",
+      "f42e426481db00582b327eb2971bca96", "6127ff289833dde0270000d8240f36b7",
+      "cc5dbaf70e2fef7729a8e2ea9937fbcf", "51850b4e3e2a3919e110376fcb6318d3",
+      "d5ac7ac25eb1b5aee293b2a2ec9de775", "64ecc00b2e24a2f07df833fb50ce09c3",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct CdefTestParam {
+  CdefTestParam(int subsampling_x, int subsampling_y, int rows4x4,
+                int columns4x4)
+      : subsampling_x(subsampling_x),
+        subsampling_y(subsampling_y),
+        rows4x4(rows4x4),
+        columns4x4(columns4x4) {}
+  int subsampling_x;
+  int subsampling_y;
+  int rows4x4;
+  int columns4x4;
+};
+
+std::ostream& operator<<(std::ostream& os, const CdefTestParam& param) {
+  return os << "subsampling(x/y): " << param.subsampling_x << "/"
+            << param.subsampling_y << ", (rows,columns)4x4: " << param.rows4x4
+            << ", " << param.columns4x4;
+}
+
+// TODO(b/154245961): rework the parameters for this test to match
+// CdefFilteringFuncs. It should cover 4x4, 8x4, 8x8 blocks and
+// primary/secondary strength combinations for both Y and UV.
+template <int bitdepth, typename Pixel>
+class CdefFilteringTest : public testing::TestWithParam<CdefTestParam> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  CdefFilteringTest() = default;
+  CdefFilteringTest(const CdefFilteringTest&) = delete;
+  CdefFilteringTest& operator=(const CdefFilteringTest&) = delete;
+  ~CdefFilteringTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    CdefInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      CdefInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      CdefInit_SSE4_1();
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        CdefInit_AVX2();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    memcpy(cur_cdef_filter_, dsp->cdef_filters, sizeof(cur_cdef_filter_));
+  }
+
+  void TestRandomValues(int num_runs);
+
+  uint16_t source_[kSourceBufferSize];
+  Pixel dest_[kMaxPlanes][kTestBufferSize];
+  int primary_strength_;
+  int secondary_strength_;
+  int damping_;
+  int direction_;
+  CdefTestParam param_ = GetParam();
+
+  CdefFilteringFuncs cur_cdef_filter_;
+};
+
+template <int bitdepth, typename Pixel>
+void CdefFilteringTest<bitdepth, Pixel>::TestRandomValues(int num_runs) {
+  const int id = static_cast<int>(param_.rows4x4 < 4) * 3 +
+                 (param_.subsampling_x + param_.subsampling_y) * 6;
+  absl::Duration elapsed_time;
+  for (int num_tests = 0; num_tests < num_runs; ++num_tests) {
+    for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+      const int subsampling_x = (plane == kPlaneY) ? 0 : param_.subsampling_x;
+      const int subsampling_y = (plane == kPlaneY) ? 0 : param_.subsampling_y;
+      const int block_width = 8 >> subsampling_x;
+      const int block_height = 8 >> subsampling_y;
+      libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed() +
+                                 id + plane);
+      const int offset = 2 * kSourceStride + 2;
+      // Fill boundaries with a large value such that cdef does not take them
+      // into calculation.
+      const int plane_width = MultiplyBy4(param_.columns4x4) >> subsampling_x;
+      const int plane_height = MultiplyBy4(param_.rows4x4) >> subsampling_y;
+      for (int y = 0; y < plane_height; ++y) {
+        for (int x = 0; x < plane_width; ++x) {
+          source_[y * kSourceStride + x + offset] =
+              rnd.Rand16() & ((1 << bitdepth) - 1);
+        }
+      }
+      for (int y = 0; y < 2; ++y) {
+        Memset(&source_[y * kSourceStride], kCdefLargeValue, kSourceStride);
+        Memset(&source_[(y + plane_height + 2) * kSourceStride],
+               kCdefLargeValue, kSourceStride);
+      }
+      for (int y = 0; y < plane_height; ++y) {
+        Memset(&source_[y * kSourceStride + offset - 2], kCdefLargeValue, 2);
+        Memset(&source_[y * kSourceStride + offset + plane_width],
+               kCdefLargeValue, 2);
+      }
+      do {
+        int strength = rnd.Rand16() & 15;
+        if (strength == 3) ++strength;
+        primary_strength_ = strength << (bitdepth - 8);
+      } while (primary_strength_ == 0);
+      do {
+        int strength = rnd.Rand16() & 3;
+        if (strength == 3) ++strength;
+        secondary_strength_ = strength << (bitdepth - 8);
+      } while (secondary_strength_ == 0);
+      damping_ = (rnd.Rand16() & 3) + 3;
+      direction_ = (rnd.Rand16() & 7);
+
+      memset(dest_[plane], 0, sizeof(dest_[plane]));
+      const absl::Time start = absl::Now();
+      const int width_index = block_width >> 3;
+      if (cur_cdef_filter_[width_index][0] == nullptr) return;
+      cur_cdef_filter_[width_index][0](
+          source_ + offset, kSourceStride, block_height, primary_strength_,
+          secondary_strength_, damping_, direction_, dest_[plane],
+          kTestBufferStride * sizeof(dest_[0][0]));
+      elapsed_time += absl::Now() - start;
+    }
+  }
+
+  for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+    const char* expected_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        expected_digest = GetDigest8bpp(id + plane);
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        expected_digest = GetDigest10bpp(id + plane);
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        expected_digest = GetDigest12bpp(id + plane);
+        break;
+#endif
+    }
+    ASSERT_NE(expected_digest, nullptr);
+    test_utils::CheckMd5Digest(kCdef, kCdefFilterName, expected_digest,
+                               reinterpret_cast<uint8_t*>(dest_[plane]),
+                               sizeof(dest_[plane]), elapsed_time);
+  }
+}
+
+// Do not test single blocks with any subsampling. 2xH and Wx2 blocks are not
+// supported.
+const CdefTestParam cdef_test_param[] = {
+    CdefTestParam(0, 0, 4, 4), CdefTestParam(0, 0, 2, 2),
+    CdefTestParam(1, 0, 4, 4), CdefTestParam(1, 0, 2, 2),
+    CdefTestParam(1, 1, 4, 4), CdefTestParam(1, 1, 2, 2),
+};
+
+using CdefFilteringTest8bpp = CdefFilteringTest<8, uint8_t>;
+
+TEST_P(CdefFilteringTest8bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefFilteringTest8bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefFilteringTest8bpp,
+                         testing::ValuesIn(cdef_test_param));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CdefFilteringTest8bpp,
+                         testing::ValuesIn(cdef_test_param));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, CdefFilteringTest8bpp,
+                         testing::ValuesIn(cdef_test_param));
+#endif
+
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, CdefFilteringTest8bpp,
+                         testing::ValuesIn(cdef_test_param));
+#endif  // LIBGAV1_ENABLE_AVX2
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using CdefFilteringTest10bpp = CdefFilteringTest<10, uint16_t>;
+
+TEST_P(CdefFilteringTest10bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefFilteringTest10bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefFilteringTest10bpp,
+                         testing::ValuesIn(cdef_test_param));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CdefFilteringTest10bpp,
+                         testing::ValuesIn(cdef_test_param));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using CdefFilteringTest12bpp = CdefFilteringTest<12, uint16_t>;
+
+TEST_P(CdefFilteringTest12bpp, Correctness) { TestRandomValues(1); }
+
+TEST_P(CdefFilteringTest12bpp, DISABLED_Speed) {
+  TestRandomValues(kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, CdefFilteringTest12bpp,
+                         testing::ValuesIn(cdef_test_param));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/convolve_test.cc b/src/dsp/convolve_test.cc
new file mode 100644
index 0000000..42cdeb7
--- /dev/null
+++ b/src/dsp/convolve_test.cc
@@ -0,0 +1,1549 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/convolve.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <ostream>
+#include <string>
+#include <tuple>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/third_party/libvpx/md5_helper.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// The convolve function will access at most (block_height + 7) rows/columns
+// from the beginning.
+constexpr int kMaxBlockWidth = kMaxSuperBlockSizeInPixels + kSubPixelTaps;
+constexpr int kMaxBlockHeight = kMaxSuperBlockSizeInPixels + kSubPixelTaps;
+
+// Test all the filters in |kSubPixelFilters|. There are 6 different filters but
+// filters [4] and [5] are only reached through GetFilterIndex().
+constexpr int kMinimumViableRuns = 4 * 16;
+
+struct ConvolveTestParam {
+  enum BlockSize {
+    kBlockSize2x2,
+    kBlockSize2x4,
+    kBlockSize4x2,
+    kBlockSize4x4,
+    kBlockSize4x8,
+    kBlockSize8x2,
+    kBlockSize8x4,
+    kBlockSize8x8,
+    kBlockSize8x16,
+    kBlockSize16x8,
+    kBlockSize16x16,
+    kBlockSize16x32,
+    kBlockSize32x16,
+    kBlockSize32x32,
+    kBlockSize32x64,
+    kBlockSize64x32,
+    kBlockSize64x64,
+    kBlockSize64x128,
+    kBlockSize128x64,
+    kBlockSize128x128,
+    kNumBlockSizes
+  };
+
+  static constexpr int kBlockWidth[kNumBlockSizes] = {
+      2, 2, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64, 128, 128};
+  static constexpr int kBlockHeight[kNumBlockSizes] = {
+      2, 4, 2, 4, 8, 2, 4, 8, 16, 8, 16, 32, 16, 32, 64, 32, 64, 128, 64, 128};
+
+  explicit ConvolveTestParam(BlockSize block_size)
+      : block_size(block_size),
+        width(kBlockWidth[block_size]),
+        height(kBlockHeight[block_size]) {}
+
+  BlockSize block_size;
+  int width;
+  int height;
+};
+
+#if !LIBGAV1_CXX17
+constexpr int ConvolveTestParam::kBlockWidth[kNumBlockSizes];   // static.
+constexpr int ConvolveTestParam::kBlockHeight[kNumBlockSizes];  // static.
+#endif
+
+const char* GetConvolveDigest8bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 16] = {
+      "ae5977a4ceffbac0cde72a04a43a9d57", "6cf5f791fe0d8dcd3526be3c6b814035",
+      "d905dfcad930aded7718587c05b48aaf", "6baf153feff04cc5b7e87c0bb60a905d",
+      "871ed5a69ca31e6444faa720895949bf", "c9cf1deba08dac5972b3b0a43eff8f98",
+      "68e2f90eaa0ab5da7e6f5776993f7eea", "f1f8282fb33c30eb68c0c315b7a4bc01",
+      "9412064b0eebf8123f23d74147d04dff", "cc08936effe309ab9a4fa1bf7e28e24e",
+      "36cbef36fa21b98df03536c918bf752a", "9d0da6321cf5311ea0bdd41271763030",
+      "55a10165ee8a660d7dddacf7de558cdd", "ac7fc9f9ea7213743fae5a023faaaf08",
+      "077e1b7b355c7ab3ca40230ee8efd8ea", "7a3e8de2a1caae206cf3e51a86dfd15a",
+      "1ddf9020f18fa7883355cf8c0881186a", "2377dd167ef2707978bed6f10ffd4e76",
+      "f918e0e4422967c6a7e47298135c7ae9", "b2264e129636368b5496760b39e64b7a",
+      "1168251e6261e2ff1fa69a93226dbd76", "4821befdf63f8c6da6440afeb57f320f",
+      "c30fc44d83821141e84cc4793e127301", "a8293b933d9f2e5d7f922ea40111d643",
+      "354a54861a94e8b027afd9931e61f997", "b384e9e3d81f9f4f9024028fbe451d8b",
+      "eeeb8589c1b31cbb565154736ca939ec", "f49dab626ddd977ed171f79295c24935",
+      "78d2f27e0d4708cb16856d7d40dc16fb", "9d2393ea156a1c2083f5b4207793064b",
+      "a9c62745b95c66fa497a524886af57e2", "2c614ec4463386ec075a0f1dbb587933",
+      "7a8856480d752153370240b066b90f6a", "beaef1dbffadc701fccb7c18a03e3a41",
+      "72b1e700c949d06eaf62d664dafdb5b6", "684f5c3a25a080edaf79add6e9137a8e",
+      "3be970f49e4288988818b087201d54da", "d2b9dba2968894a414756bb510ac389a",
+      "9a3215eb97aedbbddd76c7440837d040", "4e317feac6da46addf0e8b9d8d54304b",
+      "d2f5ca2b7958c332a3fb771f66da01f0", "7aec92c3b65e456b64ae285c12b03b0d",
+      "f72a99ad63f6a88c23724e898b705d21", "07a1f07f114c4a38ba08d2f44e1e1132",
+      "26b9de95edb45b31ac5aa19825831c7a", "4e4677a0623d44237eb8d6a622cdc526",
+      "c1b836a6ce023663b90db0e320389414", "5befcf222152ebc8d779fcc10b95320a",
+      "62adf407fc27d8682ced4dd7b55af14e", "35be0786a072bf2f1286989261bf6580",
+      "90562fc42dc5d879ae74c4909c1dec30", "a1427352f9e413975a0949e2b300c657",
+      "bcbc418bc2beb243e463851cd95335a9", "cb8fedcbecee3947358dc61f95e56530",
+      "0d0154a7d573685285a83a4cf201ac57", "b14bd8068f108905682b83cc15778065",
+      "c96c867d998473197dde9b587be14e3a", "f596c63c7b14cada0174e17124c83942",
+      "eb2822ad8204ed4ecbf0f30fcb210498", "538ce869ffd23b6963e61badfab7712b",
+      "6bbcc075f8b768a02cdc9149f150326d", "4ae70d9db2ec36885394db7d59bdd4f7",
+      "5fee162fe52c11c823db4d5ede370654", "9365186c59ef66d9def40f437022ad93",
+      "0f95fb0276c9c7910937fbdf75f2811d", "356d4003477283e157c8d2b5a79d913c",
+      "b355dab2dbb6f5869018563eece22862", "cf6ff8c43d8059cea6090a23ab66a0ef",
+      "a336f8b7bcf188840ca65c0d0e66518a", "de953f03895923359c6a719e6a537b89",
+      "8463ade9347ed602663e2cec5c4c3fe6", "392de11ffcd5c2ecf3db3480ee135340",
+      "bddd31e3e852712e6244b616622af83d", "30a36245c40d978fc8976b442a8600c3",
+      "93aa662b988b8502e5ea95659eafde59", "70440ba9ee7f9d16d297dbb49e54a56e",
+      "1eb2be4c05b50e427e29c72fa566bff5", "52c0980bae63e8459e82eee7d8af2334",
+      "75e57104d6058cd2bce1d3d8142d273d", "b4c735269ade44419169adbd852d5ddc",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "a7305087fae23de53d21a6909009ff69",
+      "8dcce009395264379c1a51239f4bb22c", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "8dcce009395264379c1a51239f4bb22c", "d90a69e7bae8aa46ed0e1e5f911d7a07",
+      "6ab4dc87be03be1dcc5d956ca819d938", "6ab4dc87be03be1dcc5d956ca819d938",
+      "8f2afdb2f03cd04ffacd421b958caaa0", "710ccecc103033088d898a2b924551fb",
+      "710ccecc103033088d898a2b924551fb", "a4093e3e5902dd659407ce6471635a4e",
+      "375d7f5358d7a088a498b8b3aaecc0d5", "375d7f5358d7a088a498b8b3aaecc0d5",
+      "08867ea5cc38c705ec52af821bc4736a", "2afb540e8063f58d1b03896486c5e89b",
+      "2afb540e8063f58d1b03896486c5e89b", "6ce47b11d2e60c5d183c84ce9f2e46cc",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "a5a1ac658d7ce4a846a32b9fcfaa3475",
+      "2370f4e4a83edf91b7f504bbe4b00e90", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "ae5464066a049622a7a264cdf9394b55", "45368b6db3d1fee739a64b0bc823ea9c",
+      "8dff0f28192d9f8c0bf7fb5405719dd8", "632738ef3ff3021cff45045c41978849",
+      "f7ec43384037e8d6c618e0df826ec029", "a6bc648197781a2dc99c487e66464320",
+      "1112ebd509007154c72c5a485b220b62", "9714c4ce636b6fb0ad05cba246d48c76",
+      "2c93dde8884f09fb5bb5ad6d95cde86d", "a49e6160b5d1b56bc2046963101cd606",
+      "7f084953976111e9f65b57876e7552b1", "0846ec82555b66197c5c45b08240fbcc",
+      "ca7471c126ccd22189e874f0a6e41960", "0802b6318fbd0969a33de8fdfcd07f10",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "3b1ceebf0579fcbbfd6136938c595b91",
+      "ecafabcad1045f15d31ce2f3b13132f2", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "5f211eba020e256a5781b203c5aa1d2e", "3b04497634364dd2cd3f2482b5d4b32f",
+      "a8ac7b5dc65ffb758b0643508a0e744e", "561ed8be43c221a561f8885a0d74c7ef",
+      "8159619fc234598c8c75154d80021fd4", "8f43645dce92cf7594aa4822aa53b17d",
+      "b6ccddb7dfa4eddc87b4eff08b5a3195", "b4e605327b28db573d88844a1a09db8d",
+      "15b00a15d1cc6cc96ca85d00b167e4dd", "7bf911888c11a9fefd604b8b9c82e9a1",
+      "bfb69b4d7d4aed73cfa75a0f55b66440", "034d1d62581bd0d840c4cf1e28227931",
+      "8cba849640e9e2859d509bc81ca94acd", "bc79acf2a0fe419194cdb4529bc7dcc8",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "3bfad931bce82335219e0e29c15f2b21",
+      "68a701313d2247d2b32636ebc1f2a008", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "05afe1f40d37a45a97a5e0aadd5066fb", "9e1f0e0bddb58d15d0925eeaede9b84c",
+      "03313cdaa593a1a7b4869010dcc7b241", "88a50d2b4107ee5b5074b2520183f8ac",
+      "ac50ea9f7306da95a5092709442989cf", "739b17591437edffd36799237b962658",
+      "b8a7eb7dd9c216e240517edfc6489397", "75b755f199dbf4a0e5ebbb86c2bd871d",
+      "31b0017ba1110e3d70b020901bc15564", "0a1aa8f5ecfd11ddba080af0051c576a",
+      "536181ee90de883cc383787aec089221", "29f82b0f3e4113944bd28aacd9b8489a",
+      "ee3e76371240d1f1ff811cea6a7d4f63", "17a20dbbf09feae557d40aa5818fbe76",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "6baf153feff04cc5b7e87c0bb60a905d",
+      "871ed5a69ca31e6444faa720895949bf", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "68e2f90eaa0ab5da7e6f5776993f7eea", "f1f8282fb33c30eb68c0c315b7a4bc01",
+      "9412064b0eebf8123f23d74147d04dff", "cc08936effe309ab9a4fa1bf7e28e24e",
+      "36cbef36fa21b98df03536c918bf752a", "9d0da6321cf5311ea0bdd41271763030",
+      "55a10165ee8a660d7dddacf7de558cdd", "ac7fc9f9ea7213743fae5a023faaaf08",
+      "077e1b7b355c7ab3ca40230ee8efd8ea", "7a3e8de2a1caae206cf3e51a86dfd15a",
+      "1ddf9020f18fa7883355cf8c0881186a", "2377dd167ef2707978bed6f10ffd4e76",
+      "f918e0e4422967c6a7e47298135c7ae9", "b2264e129636368b5496760b39e64b7a",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "4cfad2c437084a93ea76913e21c2dd89",
+      "d372f0c17bce98855d6d59fbee814c3d", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "d99ffd2579eb781c30bc0df7b76ad61e", "4e139e57cbb049a0f4ef816adc48d026",
+      "be53b2507048e7ff50226d15c0b28865", "b73f3c1a10405de89d1f9e812ff73b5a",
+      "c7d51b1f2df49ab83962257e8a5934e5", "159e443d79cc59b11ca4a80aa7aa09be",
+      "6ef14b14882e1465b0482b0e0b16d8ce", "22a8d287b425c870f40c64a50f91ce54",
+      "f1d96db5a2e0a2160df38bd96d28d19b", "637d1e5221422dfe9a6dbcfd7f62ebdd",
+      "f275af4f1f350ffaaf650310cb5dddec", "f81c4d6b001a14584528880fa6988a87",
+      "a5a2f9c2e7759d8a3dec1bc4b56be587", "2317c57ab69a36eb3bf278cf8a8795a3",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "1a0bdfc96a3b9fd904e658f238ab1076",
+      "56d16e54afe205e97527902770e71c71", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "1f7b5b8282ff3cf4d8e8c52d80ef5b4d", "79e9e260a2028c5fe320005c272064b9",
+      "2418ebcdf85551b9ae6e3725f04aae6d", "98bdf907ebacacb734c9eef1ee727c6e",
+      "4dd5672d53c8f359e8f80badaa843dfc", "a1bef519bbf07138e2eec5a91694de46",
+      "df1cb51fe1a937cd7834e973dc5cb814", "317fe65abf81ef3ea07976ef8667baeb",
+      "2da29da97806ae0ee300c5e69c35a4aa", "555475f5d1685638169ab904447e4f13",
+      "b3e3a6234e8045e6182cf90a09f767b2", "849dfeca59074525dea59681a7f88ab4",
+      "39a68af80be11e1682b6f3c4ede33530", "b22d765af176d87e7d3048b4b89b86ad",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "b8a710baa6a9fc784909671d450ecd99",
+      "f9e6a56382d8d12da676d6631bb6ef75", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "3bf8e11e18527b16f0d7c0361d74a52d", "b9ff54c6f1e3b41fc7fc0f3fa0e75cf2",
+      "06ef1504f31af5f173d3317866ca57cb", "635e8ee11cf04d73598549234ad732a0",
+      "fab693410d59ee88aa2895527efc31ac", "3041eb26c23a63a587fbec623919e2d2",
+      "c61d99d5daf575664fb7ad64976f4b03", "822f6c4eb5db760468d822b21f48d94d",
+      "3f6fcb9fae3666e085b9e29002a802fc", "d9b9fecd195736a6049c528d4cb886b5",
+      "fed17fc391e6c3db4aa14ea1d6596c87", "d0d3482d981989e117cbb32fc4550267",
+      "39561688bf6680054edbfae6035316ce", "087c5992ca6f829e1ba4ba5332d67947",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetConvolveScaleDigest8bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 2] = {
+      "0291a23f2ac4c40b5d8e957e63769904", "1d48447857472d6455af10d5526f6827",
+      "409b2278d6d372248f1891ca0dd12760", "9e416606a3f82fe5bb3f7182e4f42c2d",
+      "e126563f859ddd5c5ffde6f641168fad", "9bad4f1b7e1865f814b6fd5620816ebd",
+      "50e5e5a57185477cb2af83490c33b47c", "3d2fb301c61d7fbd0e21ac263f7ac552",
+      "5920032c6432c80c6e5e61b684018d13", "07ada64d24339488cdce492e6e0c6b0d",
+      "aaf1589aff6d062a87c627ab9ba20e3e", "91adf91bb24d2c4ea3f882bdf7396e33",
+      "1d17a932a68bb1f199f709e7725fe44b", "07716c63afda034cb386511ea25a63b5",
+      "cca17ef3324c41d189e674a059ef1255", "37d17e70619823a606c0b5f74bf2e33b",
+      "ba8ed5474c187c8e8d7f82a6a29ee860", "27663f037973ebe82ec10252a4d91299",
+      "24c27e187e8d5a2bbfa0fef9046d3eb0", "9854fdc91a48e3bd4639edcc940e5c09",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "a71907c60a9f1f81972a2859ae54a805",
+      "817bc3bf0c77abc4186eac39f2320184", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "4e7182a8b226982e2678abcf5f83325d", "50cef7c6e57544135f102226bb95bed9",
+      "225e054dbcfff05b1c8b0792c731449e", "16eb63f03839159f3af0e08be857170f",
+      "c8e5d111a2e3f4487330a8bd893cb894", "4fd99eaf9c160442aab35b9bdc5d275b",
+      "8b0f61bfb30747d4c9215618ac42557c", "1df78022da202cefb9a8100b114152d9",
+      "378466e1eda63dbc03565b78af8e723f", "28ea721411fbf5fc805035be9a384140",
+      "4fed5d4163a3bfcc6726a42f20410b0a", "55abfca0c820771bd926e4b94f66a499",
+      "6c8b8ef0a78859c768e629e1decc0019", "d0ead286b5ba3841d24dd114efbfef0a",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetConvolveDigest10bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 16] = {
+      "b1b6903d60501c7bc11e5285beb26a52", "a7855ed75772d7fa815978a202bbcd9f",
+      "bde291a4e8087c085fe8b3632f4d7351", "238980eebc9e63ae3eea2771c7a70f12",
+      "0eac13431bd7d8a573318408a72246d5", "d05a237ed7a9ca877256b71555b1b8e4",
+      "73438155feb62595e3e406921102d748", "5871e0e88a776840d619670fbf107858",
+      "1c6376ce55c9ee9e35d432edb1ffb3b7", "d675e0195c9feca956e637f3f1959f40",
+      "b5681673903ade13d69e295f82fdd009", "3c43020105ae93a301404b4cd6238654",
+      "dd2c5880a94ed3758bfea0b0e8c78286", "4ebb1a7b25a39d8b9868ec8a1243103f",
+      "d34ec07845cd8523651e5f5112984a14", "2ce55308d873f4cd244f16da2b06e06e",
+      "a4bb5d5ff4b25f391265b5231049a09a", "c9106e0c820b03bcdde3aa94efc11a3e",
+      "7ec2eae9e118506da8b33440b399511a", "78de867c8ee947ed6d29055747f26949",
+      "a693b4bd0334a3b98d45e67d3985bb63", "156de3172d9acf3c7f251cd7a18ad461",
+      "e545b8a3ff958f8363c7968cbae96732", "7842b2047356c1417d9d88219707f1a1",
+      "1a487c658d684314d91bb6d961a94672", "94b3e5bcd6b849b66a4571ec3d23f9be",
+      "0635a296be01b7e641de98ee27c33cd2", "82dc120bf8c2043bc5eee81007309ebf",
+      "58c826cad3c14cdf26a649265758c58b", "f166254037c0dfb140f54cd7b08bddfe",
+      "74ab206f14ac5f62653cd3dd71a7916d", "5621caef7cc1d6522903290ccc5c2cb8",
+      "78ec6cf42cce4b1feb65e076c78ca241", "42188e2dbb4e02cd353552ea147ad03f",
+      "f9813870fc27941a7c00a0443d7c2fe7", "20b14a6b5af7aa356963bcaaf23d230d",
+      "9c9c41435697f75fa118b6d6464ee7cb", "38816245ed832ba313fefafcbed1e5c8",
+      "5d34137cc8ddba75347b0fa1d0a91791", "465dcb046a0449b9dfb3e0b297aa3863",
+      "3e787534dff83c22b3033750e448865a", "4c91f676a054d582bcae1ca9adb87a31",
+      "eab5894046a99ad0a1a12c91b0f37bd7", "765b4cfbfc1a4988878c412d53bcb597",
+      "bc63b29ec78c1efec5543885a45bb822", "91d6bdbc62d4bb80c9b371d9704e3c9e",
+      "cecd57396a0033456408f3f3554c6912", "5b37f94ef136c1eb9a6181c19491459c",
+      "716ba3a25b454e44b46caa42622c128c", "9076f58c4ab20f2f06d701a6b53b1c4f",
+      "d3212ab3922f147c3cf126c3b1aa17f6", "b55fea77f0e14a8bf8b6562b766fe91f",
+      "59b578268ff26a1e21c5b4273f73f852", "16761e7c8ba2645718153bed83ae78f6",
+      "a9e9805769fe1baf5c7933793ccca0d8", "553a2c24939dff18ec5833c77f556cfb",
+      "5c1ec75a160c444fa90abf106fa1140e", "2266840f11ac4c066d941ec473b1a54f",
+      "9e194755b2a37b615a517d5f8746dfbb", "bbf86f8174334f0b8d869fd8d58bf92d",
+      "fd1da8d197cb385f7917cd296d67afb9", "a984202c527b757337c605443f376915",
+      "c347f4a58fd784c5e88c1a23e4ff15d2", "29cbaadbff9adf4a3d49bd9900a9dd0b",
+      "c5997b802a6ba1cf5ba1057ddc5baa7e", "4f750f6375524311d260306deb233861",
+      "59f33727e5beeb783a057770bec7b4cd", "0654d72f22306b28d9ae42515845240c",
+      "6c9d7d9e6ef81d76e775a85c53abe209", "a35f435ccc67717a49251a07e62ae204",
+      "c5325015cb0b7c42839ac4aa21803fa0", "f81f31f1585c0f70438c09e829416f20",
+      "ab10b22fb8dd8199040745565b28595d", "0d928d6111f86c60ccefc6c6604d5659",
+      "4ed1a6200912995d4f571bdb7822aa83", "92e31a45513582f386dc9c22a57bbbbd",
+      "6dbf310a9c8d85f76306d6a35545f8af", "80fce29dc82d5857c1ed5ef2aea16835",
+      "14f2c5b9d2cd621c178a39f1ec0c38eb", "da54cfb4530841bda29966cfa05f4879",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "7e3fa9c03bc3dfbdeb67f24c5d9a49cd",
+      "f3454ca93cbb0c8c09b0695d90a0df3d", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "f3454ca93cbb0c8c09b0695d90a0df3d", "1a77d2af4d2b6cf8737cfbcacacdc4e4",
+      "89bec831efea2f88129dedcad06bb3fa", "89bec831efea2f88129dedcad06bb3fa",
+      "dead0fe4030085c22e92d16bb110de9d", "306a2f5dfd675df4ed9af44fd5cac8c0",
+      "306a2f5dfd675df4ed9af44fd5cac8c0", "9d01c946a12f5ef9d9cebd9816e06014",
+      "768f63912e43148c13688d7f23281531", "768f63912e43148c13688d7f23281531",
+      "2e7927158e7b8e40e7269fc909fb584b", "123028e18c2bfb334e34adb5a4f67de4",
+      "123028e18c2bfb334e34adb5a4f67de4", "2c979c2bddef79a760e72a802f83cc76",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "da1a6ff2be03ec8acde4cb1cd519a6f0",
+      "a4ca37cb869a0dbd1c4a2dcc449a8f31", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "1b5d1d4c7be8d5ec00a42a49eecf918f", "98b77e88b0784baaea64c98c8707fe46",
+      "8148788044522edc3c497e1017efe2ce", "acf60abeda98bbea161139b915317423",
+      "262c96b1f2c4f85c86c0e9c77fedff1e", "f35a3d13516440f9168076d9b07c9e98",
+      "13782526fc2726100cb3cf375b3150ed", "13c07441b47b0c1ed80f015ac302d220",
+      "02880fde51ac991ad18d8986f4e5145c", "aa25073115bad49432953254e7dce0bc",
+      "69e3361b7199e10e75685b90fb0df623", "2f8ab35f6e7030e82ca922a68b29af4a",
+      "452f91b01833c57db4e909575a029ff6", "1fabf0655bedb671e4d7287fec8119ba",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "d54206c34785cc3d8a06c2ceac46378c",
+      "85a11892ed884e3e74968435f6b16e64", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "16434230d24b9522ae2680e8c37e1b95", "963dea92f3efbb99137d1de9c56728d3",
+      "b72fb6a9a073c2fe65013af1842dc9b0", "86fa0c299737eb499cbcdce94abe2d33",
+      "6b80af04470b83673d98f46925e678a5", "65baca6167fe5249f7a839ce5b2fd591",
+      "e47ded6c0eec1d5baadd02aff172f2b1", "c0950e609f278efb7050d319a9756bb3",
+      "9051290279237f9fb1389989b142d2dd", "34cdc1be291c95981c98812c5c343a15",
+      "5b64a6911cb7c3d60bb8f961ed9782a2", "7133de9d03a4b07716a12226b5e493e8",
+      "3594eff52d5ed875bd9655ddbf106fae", "90d7e13aa2f9a064493ff2b3b5b12109",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "b1f26ee13df2e14a757416ba8a682278",
+      "996b6c166f9ed25bd07ea6acdf7597ff", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "34895d4c69a6c3303693e6f431bcd5d8", "c9497b00cb1bc3363dd126ffdddadc8e",
+      "1e461869bb2ee9b6069c5e52cf817291", "8d7f1d7ea6a0dcc922ad5d2e77bc74dd",
+      "138855d9bf0ccd0c62ac14c7bff4fd37", "64035142864914d05a48ef8e013631d0",
+      "205904fa3c644433b46e01c11dd2fe40", "291425aaf8206b20e88db8ebf3cf7e7f",
+      "cb6238b8eb6b72980958e6fcceb2f2eb", "626321a6dfac542d0fc70321fac13ff3",
+      "1c6fda7501e0f8bdad972f7857cd9354", "4fd485dadcb570e5a0a5addaf9ba84da",
+      "d3f140aea9e8eabf4e1e5190e0148288", "e4938219593bbed5ae638a93f2f4a580",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "238980eebc9e63ae3eea2771c7a70f12",
+      "0eac13431bd7d8a573318408a72246d5", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "73438155feb62595e3e406921102d748", "5871e0e88a776840d619670fbf107858",
+      "1c6376ce55c9ee9e35d432edb1ffb3b7", "d675e0195c9feca956e637f3f1959f40",
+      "b5681673903ade13d69e295f82fdd009", "3c43020105ae93a301404b4cd6238654",
+      "dd2c5880a94ed3758bfea0b0e8c78286", "4ebb1a7b25a39d8b9868ec8a1243103f",
+      "d34ec07845cd8523651e5f5112984a14", "2ce55308d873f4cd244f16da2b06e06e",
+      "a4bb5d5ff4b25f391265b5231049a09a", "c9106e0c820b03bcdde3aa94efc11a3e",
+      "7ec2eae9e118506da8b33440b399511a", "78de867c8ee947ed6d29055747f26949",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "e552466a4e7ff187251b8914b084d404",
+      "981b7c44b6f7b7ac2acf0cc4096e6bf4", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "a4c75372af36162831cb872e24e1088c", "497271227a70a72f9ad25b415d41563f",
+      "c48bd7e11ec44ba7b2bc8b6a04592439", "0960a9af91250e9faa1eaac32227bf6f",
+      "746c2e0f96ae2246d534d67102be068c", "d6f6db079da9b8909a153c07cc9d0e63",
+      "7c8928a0d769f4264d195f39cb68a772", "db645c96fc8be04015e0eb538afec9ae",
+      "946af3a8f5362def5f4e27cb0fd4e754", "7ad78dfe7bbedf696dd58d9ad01bcfba",
+      "f0fd9c09d454e4ce918faa97e9ac10be", "af6ae5c0eb28417bd251184baf2eaba7",
+      "866f8df540dd3b58ab1339314d139cbd", "72803589b453a29501540aeddc23e6f4",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "aba5d5ef5e96fe418e65d20e506ea834",
+      "d70bf16e2a31e90b7b3cdeaef1494cf9", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "6df80bb7f264f4f285d09a4d61533fae", "c8831118d1004a7cca015a4fca140018",
+      "b7f82c140369067c105c7967c75b6f9e", "130f47aae365aabfec4360fa5b5ff554",
+      "92483ed631de21b685ffe6ccadbbec8f", "cbb6ab31547df6b91cfb48630fdffb48",
+      "1eea5e8a24d6aa11778eb3e5e5e9c9f2", "9e193b6b28ce798c44c744efde19eee9",
+      "885c384d90aaa34acd8303958033c252", "8110ed10e7234851dff3c7e4a51108a2",
+      "6fb9383302eb7e7a13387464d2634e03", "864d51fcc737bc73a3f588b67515039a",
+      "2ecb7890f00234bcb28c1d969f489012", "c4793d431dbf2d88826bb440bf027512",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "972aeba65e8a6d20dd0f95279be2aa75",
+      "34165457282e2af2e9b3f5840e4dec5d", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "b8c5582b9bbb789c45471f93be83b41f", "257bf5467db570974d7cf2356bacf116",
+      "5255dded79f56b0078543b5a1814a668", "ef745100f5f34c8ff841b2b0b57eb33f",
+      "edae8ed67286ca6a31573a541b3deb6f", "01adcd8bf15fbf70df47fbf3a953aa14",
+      "ba539808a8501609ce052a1562a62b25", "ac8e6391200cec2abdebb00744a2ba82",
+      "54b17120f7d71ddb4d70590ecd231cc1", "f6e36446a97611a4db4425df926974b2",
+      "a82f4080699300b659bbe1b5c4463147", "ecedb178f7cad3dc1b921eca67f9efb6",
+      "0609ca0ff3ca90069e8b48829b4b0891", "839e86c681e97359f7819c766000dd1c",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetConvolveScaleDigest10bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 2] = {
+      "27e21eb31687f9fbd0a66865fa8d7c8a", "9bff726c8e1d0998451a3b9cf2b3d8c8",
+      "661d74cfef36f12ed8d9b4c3ccb7fe0d", "5fc365fd1fcc9599dd97a885ba0c2eec",
+      "acdba2c82a6268e3c0ae8fc32be1b41f", "a5db60bbeaf56ab030ed21c42d553cf3",
+      "1228bb633f9fd63fdb998b775ca79e98", "07812c97f9f43a2a8ae07329dc488699",
+      "903525fb782119c4dfaf61b98a310c9f", "f38b51cef38b929e317861ccbc73ecd8",
+      "b78b05138e1d5fbf089144c42ce03058", "f2e227664cbf2d821b242a34fcbc9835",
+      "cb992dac70591e7d3663588ae13b9adc", "f2292d33657d939fa85ea5bacdfe39a3",
+      "7049dc742d6d8ad6f5d4309968ff281c", "e4beebde1ac335a4d92e4af94653a2ce",
+      "cc77875f98f54b9b26b5f7d9fcbc828d", "fb623f7b9e1ffcf2ae361599728a5589",
+      "c33847e47a7eda214734084640818df9", "ab3e1aec3d720c0c89c46a8d5b161b44",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "efe4de861dcf0f7458b6208cae7e3584",
+      "814751c55fa84f0fed94ff15fc30fc24", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "31a63fe47297102937acbe7a328588b7", "b804a0a24633243f7da48d7a5f51c0bf",
+      "cb492672b005fc378cccc8c03003cd4a", "1d18732bcf2ea487e84579489cc59a22",
+      "457c4b3ec38a8d6c210584ade1a9fae2", "a3afdd468e6a5238a3dbd2cc21c11c9e",
+      "6ff8a16f21d6e8a9741dacf0734ae563", "3ffa29ef7e54e51f6849c9a3d3c79d03",
+      "af89899b083cf269ac1bd988aeb15b15", "3365d8411c11081fb228436238b9a671",
+      "3ba56d30f5f81d7098f356635a58b9af", "b3013776900c6520bd30f868e8c963b6",
+      "81febaa7342692483040f500ba2e5e2b", "4a51ff1d9a4a68687d590b41aa7835a3",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetConvolveDigest12bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 16] = {
+      "e25031afae184cc4d186cde7e3d51e33", "6fb55dec2506dae6c229469cdf2e7d83",
+      "9df34d27f5bd040d1ed1455b151cd1ff", "7f6829458f00edb88f78851dd1a08739",
+      "a8bbe9b6b9eaf6f681d91c981b994949", "21f74980b36cb246426f4bc3fe7c08c3",
+      "403c2ccced3b5b141a4c7559c0cd841b", "1c3c4c6cd8a3e79cd95d6038531b47e5",
+      "f18d6950d36619086ac0055bab528cb1", "37d9c5babddf24fe8cb061297297b769",
+      "c111000d4021381f3d18ea0e24a1b5f5", "4e1e4f0a592ff028e35f8187627d6e68",
+      "0ca9ad4614d32da05746f8712a46d861", "8a122ab194e2fdb7089b29be50af8c86",
+      "3c21326e22a80982d1b0ffc09be4beae", "f6c8d1fe2c1fb19604c49c6a49bd26a8",
+      "d3eda9d7aa80e4ea1f18bf565b143e57", "fe21bd1cb8e90466dc727f2223ea7aed",
+      "01efe3df83c715325aaddd4d4ce130ad", "ecaa751360121d3746b72932415fb998",
+      "291e67095399651dc5c8a033390f255f", "66b26828e434faf37ddc57d3e0abb6db",
+      "e9cd69e9ba70864e3d0b175ac0a177d6", "64e4db895a843cb05384f5997b1ba978",
+      "f305161c82de999d2c93eac65f609cfe", "4762b2bd27983ad916ec0a930c0eca6b",
+      "1631495ffae43a927267ebd476015ef1", "b0f22de7b10057e07af71f9bce4615ce",
+      "6fa29dc4be1a46d246a41d66a3d35cb4", "734601c2185bdf30ba9ded8b07003a05",
+      "524e4553d92c69e7e4ed934f7b806c6b", "3709c8950bc5fcc4a2b3ec68fc78bf7e",
+      "69c274d9f8e0fd6790495e9695251f1f", "ee30cc1232c27494ef53edd383568f25",
+      "e525dbeb0b4341952a92270dcfc51730", "b3685c9e783d3402497bbd49d28c7dd7",
+      "d1c9f02dc818e6b974794dfb7749aac8", "bdb9e4961f9aa8c25568d3394e968518",
+      "f5f74555adcad85f3ebd3cb85dc7b770", "737e2a0be806dbd701014f2078be7898",
+      "20a18294e3a9422193aa0a219fd80ede", "7106648ecb9ae24a54d1dbabf2a9e318",
+      "20f39cbd6b5ed87a6ae4f818932325c0", "a99666e3157e32a07c87b01e52091a76",
+      "123e4d533d478c3089c975323c85396b", "d2a8021f7683a0cdf2658418fa90a6fc",
+      "1437e192a3349db8702d5b90eb88dbc1", "fe097fc4aeed7cda0b0f405124efb19d",
+      "1988227c51fa589db1307fd890bb5972", "537e25a6c30b240dc1e3bddd1c3a0a03",
+      "aebe5cffaae448db5a08987a3375a428", "7127ae9bdc63df4459590dc02ca95403",
+      "7ad281903a210f2b1f39f7c40c8df272", "d4b97ba21f7b400ba9f9cd8bb1a576df",
+      "0884a824203aaf72c78f73fdaf2b23a2", "63d60388605c92daee55d517de622a9e",
+      "171ec49a779de1efa69510eefbd09bba", "541cf051579c5a10b9debd3bfdcb7f32",
+      "91c14451ad93ed88e96b5d639ce408de", "3b0313ec0e043d19744bf88c90e875a1",
+      "6adcb3cee91fe3a83b36deb11c5ad6dd", "c6d4bfad24616a88222681992a99d782",
+      "515dc0f2a41730d5c434e4f3c81b02c3", "1c69abdee3b9608a6094034badc2bec0",
+      "1785a0f321d7dd90aa8846961737a767", "dd12c5b8c341f2423d0d5db4f285d199",
+      "5741fb69aae1ca8a0fbe4f1478df88ef", "a4390ceb4e4e9f5cf6a47a9b11a97015",
+      "6778eb25df902092b440c3402e7f0f80", "5ad9d6b36f8898bb55e901c1c0c523da",
+      "73969b6c03bb5a7345a8b968b542668e", "f48192947e66d70f116193a4186d0186",
+      "53f60d0e89d7d994ec6d6131fb7e75ae", "c75f6f8813839ae3cf192baa29039265",
+      "9ff0852ebbad56663250f86ac3a3bf9b", "668938580a770ea7ace8bbf7d349e89f",
+      "5b06bb0a15ac465a250d9b209f05289f", "a2128f5c8692fed7e7c1c7af22ce9f72",
+      "f80f1d7a58869ec794258c0f7df14620", "ed1e03a35924c92ed2fc9808dc3f06f3",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "35ef89c35d2e8e46feb856c554c21c9f",
+      "b98ce33a1bf4fab840b7ef261b30dbc4", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "b98ce33a1bf4fab840b7ef261b30dbc4", "42263fb359c4fdf1c7cdb4980b3e97f2",
+      "1e7071b7db3144188bdcf5d199fe5355", "1e7071b7db3144188bdcf5d199fe5355",
+      "30d367304a87bd25f0ad2ff8e4b5eb41", "4abe6dbb3198219015838dbedf07297a",
+      "4abe6dbb3198219015838dbedf07297a", "acec349a95b5bba98bb830372fa15e73",
+      "a73ad8661256ce2fdf5110425eb260b2", "a73ad8661256ce2fdf5110425eb260b2",
+      "8ff2f049d3f972867f14775188fe589b", "87f5f9a07aea75c325e6d7ff6c96c7c2",
+      "87f5f9a07aea75c325e6d7ff6c96c7c2", "325fcde7d415d7aa4929a3ea013fb9cc",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "05aa29814d5ce35389dbcf20368850da",
+      "fbb89f907a040e70953e3364dbe1feda", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "44ac511baf45032078cc0b45e41dba79", "efb98974adc58d88e122293436bb9184",
+      "7eee18c1a16bcb4e7ef7b27f68ba884f", "b0904c9b118dd9a1f9f034c0ff82d1c1",
+      "54436deb5183dd9669dd4f5feadb3850", "4db1c310b7d9a8bd3e2b5d20fa820e3b",
+      "c40abc6b2d67527f48a287cd7e157428", "48ec3fcf509805f484c8e0948c3469be",
+      "cb7d4a76fa7de52ed2fe889785327b38", "f57983346815fa41e969c195c1c03774",
+      "7dba59b0de2c877666ded6bdaefdcc30", "4837f8ba2f67f17f28a38c5e2a434c73",
+      "09e06fe9dc7ef7818f2a96895235afd4", "002976970ec62b360f956b9c091782d4",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "78673b1084367e97b8dd83990adc5219",
+      "06b5d4a30b9efb6c1d95ef7957f49e76", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "ce460146922cd53970b510d460aa4062", "6fd051938b8efcec9ece042f1edc177a",
+      "f5ff0dcfe3c1a56e3856549d8ded416b", "b69bc2cfc17c6b4313264db96831f0d1",
+      "38a5e65bd71934becfb376eb3b9bc513", "32c1163aa4ca6b6c69d950aba7b06d48",
+      "0c22a6c014c6347983de4ca863f3b53f", "a80c5ee9eb2dfb9a0d56e92eb3f85d91",
+      "a9719722a150a81175427bc161b95d7a", "8237befd456131a488cc5b8b63f4aca5",
+      "51616abcd0beea53a78ffce106b974fc", "6c47b22270f01d27b404da07e1be1202",
+      "356268298d3887edaabd0169a912c94e", "d2b00216e106cb8c5450e2eff1f8481a",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "c2de3a582c79aee811076211c497d2bc",
+      "d1b6d9c73da41def26dd4f85fbd1bde8", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "d8374eb7825081b89f74b05c66bccd63", "d5f7d68c10b5eaf0fba6f93ee26266e6",
+      "94d19cb65f29db65e6656b588f431ade", "5126e95f0249024a6f6d426714bd5b20",
+      "d7d3654b9c2dabe13239875984770acd", "6491afd5d651aab80aa179b579b74341",
+      "037a5de0de89983808f8e8f6dc39110f", "5980073b7685c5c9b2ec027e06be2cbc",
+      "0abb9d035aca426b62ca0f3fab063bab", "fe002a902bb4ec24dfe3ea0fe381a472",
+      "1ac15726df1aa2cd8855162a91893379", "0758c3ac16467605d73c725a697c3dc1",
+      "97d894d85f6ccfa4ff81e0e8fdf03da1", "c3c7b362f063a18244ea542a42d2873c",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "7f6829458f00edb88f78851dd1a08739",
+      "a8bbe9b6b9eaf6f681d91c981b994949", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "403c2ccced3b5b141a4c7559c0cd841b", "1c3c4c6cd8a3e79cd95d6038531b47e5",
+      "f18d6950d36619086ac0055bab528cb1", "37d9c5babddf24fe8cb061297297b769",
+      "c111000d4021381f3d18ea0e24a1b5f5", "4e1e4f0a592ff028e35f8187627d6e68",
+      "0ca9ad4614d32da05746f8712a46d861", "8a122ab194e2fdb7089b29be50af8c86",
+      "3c21326e22a80982d1b0ffc09be4beae", "f6c8d1fe2c1fb19604c49c6a49bd26a8",
+      "d3eda9d7aa80e4ea1f18bf565b143e57", "fe21bd1cb8e90466dc727f2223ea7aed",
+      "01efe3df83c715325aaddd4d4ce130ad", "ecaa751360121d3746b72932415fb998",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "67b2ea94cc4d0b32db3ae3c29eee4d46",
+      "bcfec99ad75988fa1efc1733204f17f2", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "79c222c5796e50119f1921e7bc534a25", "ae3f7c189458f044e9c52399d37a55e2",
+      "fd6dde45bd2937331428de9ef4f8e869", "b384d065423f3d271b85781d76a73218",
+      "466ea0680c06f59e8b3bb293608731fb", "360541ba94f42d115fe687a97a457ffb",
+      "e5a0794d37af40c40a4d2c6d3f7d2aa2", "4eed285651a75614bd60adebbe2e185c",
+      "bbdbf93942282d7b9c4f07591a1764a6", "1288a9ec3e6f79213b6745e6e7568c44",
+      "4ff1310bfd656d69ed5c108a91a9b01a", "3380806b5f67eb3ebce42f8e7c05b256",
+      "09c4bdf0f30aca6812fb55a5ac06b1bd", "722c86ba6bf21f40742ee33b4edc17c4",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "f5303c96d1630f9840eaaba058cd818b",
+      "c20cd45782b2f52c05e4189912047570", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "d6360f96fe15a3ee1e903b0a53dcaaeb", "4b18995cdf2f5d18410d3a732c5932b1",
+      "6f62bf7395c3dfccc1565ba8424f20e8", "c9987ed30491cd28bbc711dd57228247",
+      "8e277ec837cbecf529ae2eb0578fddc1", "c0c132386f23c5f0fba055a12fb79547",
+      "6b5617ab78dd0916690dfa358298b7b3", "394abedca37f60d1a5148a4c975305ed",
+      "bb88881e0e4cf2d88c2d2b38b5833f20", "bef10806be8d58ea8e97870a813b075e",
+      "b4b017d1f792bea69d3b773db7c80c7c", "0660bc63041213a8a4d74724a3bc4291",
+      "5050c8c5388a561691fd414b00c041df", "9ed40c68de6a8008a902d7224f8b620f",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "ec10ce4a674424478a401847f744251d",
+      "bdd897eafc8ef2651a7bba5e523a6ac2", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "2745de4a6b29abb85ee513e22ad362c3", "8aaad384b7cd349b4b968e657ec15523",
+      "fb6c0723432bcd2246d51a90f5fb5826", "f8104ed5921ebd48c6eed16150ffe028",
+      "85c2e236b3e32bf731601237cf0594cd", "8bd6eefff9640766cdf64ab082cb1485",
+      "78b5cd9dde6c6a5900f3040c57172091", "aaa980506bd7bb1d75924a8025698d1a",
+      "90050a411d501f7166f6741832b0c342", "d6ec88b2c38e32511f3359e1d5f9d85b",
+      "96506b8b39274c8fe687ea39761997f1", "3322ea83995c2762fb60db993b401658",
+      "151b6e4ce60392639982fca5a73ac3d3", "d52a1038e135bef233674a843f8c7cb6",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetConvolveScaleDigest12bpp(int id) {
+  // Entries containing 'XXXXX...' are skipped. See the test for details.
+  static const char* const kDigest[ConvolveTestParam::kNumBlockSizes * 2] = {
+      "aea59b7a638f27acad2b90fd2b8c9fee", "be87ba981a0af25611a7d5f0970be9b3",
+      "7c81f1486cd607376d776bf2c6e81dec", "f683ba2a9b353bea35f26c1ed730f3c5",
+      "11e2d70daff1726093cb4fcae33ce0d6", "567575eac0dea2f379019b2d4bafe444",
+      "216479ed580d6e0d7c1d523015394814", "dcabbe5f5709a4b6634d77cc514e863a",
+      "4e888207fe917faeea2b44383ac16caf", "d617c5608fae3b01c507c7e88040fee3",
+      "eeac5d9b3dc005e76f13dfc7483eae48", "8ff0a82811f77303c4516bb8c761336f",
+      "95a7c315aaa208097b6ab006f1d07654", "da63527ee80e6772435cff8321a29a95",
+      "404457f72e7113d1f3797a39319fd3fe", "43cbccfe2663ec11c157319acfe629a5",
+      "1dc5b8dee4542f3d7fcf6b0fa325dfde", "16d4506674f2fcedfcd1e006eb097141",
+      "4fcf329ddb405cd6bbb0a6fb87e29eb3", "de77a781957653ea1750f79995605cdc",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "436f6fdc008d94a94bc6f516f98f402f",
+      "b436bd9036f08ba7e50cfc536911dbbd", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+      "720a01018856bd83f4d89a9024b14728", "b7e01a3f161007712ce342f59b2c51f2",
+      "922420ebe5dec4f19c259ebdf8a3259a", "979aaba579556207a7bbcc939123c1b2",
+      "89a30898cbaa4d64f9072173e8365864", "0586ff961f2e4228f4e38299fb25ae07",
+      "adb27a03f8b1b50fe2a52b5ca8d4fc28", "4f91cd92aab2e09f4b123251a8d2f219",
+      "620fba0fff163d96a1cd663d1af4a4c5", "bf7a0fa65b1a90ba34c834558fa2c86e",
+      "c21f7d7d16d047a27b871a7bf8476e2d", "a94b17c81f3ce2b47081bd8dd762a2e5",
+      "9078d20f59bc24862af3856acb8c0357", "ee510ce6b3d22de9e4bd7920a26fd69a",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct ConvolveTypeParam {
+  ConvolveTypeParam(bool is_intra_block_copy, bool is_compound,
+                    bool has_vertical_filter, bool has_horizontal_filter)
+      : is_intra_block_copy(is_intra_block_copy),
+        is_compound(is_compound),
+        has_vertical_filter(has_vertical_filter),
+        has_horizontal_filter(has_horizontal_filter) {}
+  bool is_intra_block_copy;
+  bool is_compound;
+  bool has_vertical_filter;
+  bool has_horizontal_filter;
+};
+
+std::ostream& operator<<(std::ostream& os, const ConvolveTestParam& param) {
+  return os << "BlockSize" << param.width << "x" << param.height;
+}
+
+std::ostream& operator<<(std::ostream& os, const ConvolveTypeParam& param) {
+  return os << "is_intra_block_copy: " << param.is_intra_block_copy
+            << ", is_compound: " << param.is_compound
+            << ", has_(vertical/horizontal)_filter: "
+            << param.has_vertical_filter << "/" << param.has_horizontal_filter;
+}
+
+//------------------------------------------------------------------------------
+template <int bitdepth, typename Pixel>
+class ConvolveTest : public testing::TestWithParam<
+                         std::tuple<ConvolveTypeParam, ConvolveTestParam>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  ConvolveTest() = default;
+  ~ConvolveTest() override = default;
+
+  void SetUp() override {
+    ConvolveInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    GetConvolveFunc(dsp, &base_convolve_func_);
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_convolve_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        ConvolveInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        ConvolveInit_AVX2();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      ConvolveInit_NEON();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      ConvolveInit10bpp_NEON();
+#endif
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    GetConvolveFunc(dsp, &cur_convolve_func_);
+
+    // Skip functions that have not been specialized for this particular
+    // architecture.
+    if (cur_convolve_func_ == base_convolve_func_) {
+      cur_convolve_func_ = nullptr;
+    }
+  }
+
+ protected:
+  int GetDigestId() const {
+    int id = param_.block_size;
+    id += param_.kNumBlockSizes *
+          static_cast<int>(type_param_.has_horizontal_filter);
+    id += 2 * param_.kNumBlockSizes *
+          static_cast<int>(type_param_.has_vertical_filter);
+    id += 4 * param_.kNumBlockSizes * static_cast<int>(type_param_.is_compound);
+    id += 8 * param_.kNumBlockSizes *
+          static_cast<int>(type_param_.is_intra_block_copy);
+    return id;
+  }
+
+  void GetConvolveFunc(const Dsp* dsp, ConvolveFunc* func);
+  void SetInputData(bool use_fixed_values, int value);
+  void Check(bool use_fixed_values, const Pixel* src, const Pixel* dest,
+             libvpx_test::MD5* md5_digest);
+  void Check16Bit(bool use_fixed_values, const uint16_t* src,
+                  const uint16_t* dest, libvpx_test::MD5* md5_digest);
+  // |num_runs| covers the categories of filters (6) and the number of filters
+  // under each category (16).
+  void Test(bool use_fixed_values, int value,
+            int num_runs = kMinimumViableRuns);
+
+  const ConvolveTypeParam type_param_ = std::get<0>(GetParam());
+  const ConvolveTestParam param_ = std::get<1>(GetParam());
+
+ private:
+  ConvolveFunc base_convolve_func_;
+  ConvolveFunc cur_convolve_func_;
+  // Convolve filters are 7-tap, which need 3 pixels
+  // (kRestorationHorizontalBorder) padding.
+  Pixel source_[kMaxBlockHeight * kMaxBlockWidth] = {};
+  uint16_t source_16bit_[kMaxBlockHeight * kMaxBlockWidth] = {};
+  uint16_t dest_16bit_[kMaxBlockHeight * kMaxBlockWidth] = {};
+  Pixel dest_clipped_[kMaxBlockHeight * kMaxBlockWidth] = {};
+
+  const int source_stride_ = kMaxBlockWidth;
+  const int source_height_ = kMaxBlockHeight;
+};
+
+template <int bitdepth, typename Pixel>
+void ConvolveTest<bitdepth, Pixel>::GetConvolveFunc(const Dsp* const dsp,
+                                                    ConvolveFunc* func) {
+  *func =
+      dsp->convolve[type_param_.is_intra_block_copy][type_param_.is_compound]
+                   [type_param_.has_vertical_filter]
+                   [type_param_.has_horizontal_filter];
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveTest<bitdepth, Pixel>::SetInputData(bool use_fixed_values,
+                                                 int value) {
+  if (use_fixed_values) {
+    std::fill(source_, source_ + source_height_ * source_stride_, value);
+  } else {
+    const int offset =
+        kConvolveBorderLeftTop * source_stride_ + kConvolveBorderLeftTop;
+    const int mask = (1 << bitdepth) - 1;
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    const int height = param_.height;
+    const int width = param_.width;
+    for (int y = 0; y < height; ++y) {
+      for (int x = 0; x < width; ++x) {
+        source_[y * source_stride_ + x + offset] = rnd.Rand16() & mask;
+      }
+    }
+    // Copy border pixels to the left and right borders.
+    for (int y = 0; y < height; ++y) {
+      Memset(&source_[(y + kConvolveBorderLeftTop) * source_stride_],
+             source_[y * source_stride_ + offset], kConvolveBorderLeftTop);
+      Memset(&source_[y * source_stride_ + offset + width],
+             source_[y * source_stride_ + offset + width - 1],
+             kConvolveBorderLeftTop);
+    }
+    // Copy border pixels to the top and bottom borders.
+    for (int y = 0; y < kConvolveBorderLeftTop; ++y) {
+      memcpy(&source_[y * source_stride_],
+             &source_[kConvolveBorderLeftTop * source_stride_],
+             source_stride_ * sizeof(Pixel));
+      memcpy(&source_[(y + kConvolveBorderLeftTop + height) * source_stride_],
+             &source_[(kConvolveBorderLeftTop + height - 1) * source_stride_],
+             source_stride_ * sizeof(Pixel));
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveTest<bitdepth, Pixel>::Check(bool use_fixed_values,
+                                          const Pixel* src, const Pixel* dest,
+                                          libvpx_test::MD5* md5_digest) {
+  if (use_fixed_values) {
+    // For fixed values, input and output are identical.
+    const bool success =
+        test_utils::CompareBlocks(src, dest, param_.width, param_.height,
+                                  kMaxBlockWidth, kMaxBlockWidth, false, false);
+    EXPECT_TRUE(success);
+  } else {
+    // For random input, compare md5.
+    const int offset =
+        kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+    const size_t size = sizeof(dest_clipped_) - offset * sizeof(Pixel);
+    md5_digest->Add(reinterpret_cast<const uint8_t*>(dest), size);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveTest<bitdepth, Pixel>::Check16Bit(bool use_fixed_values,
+                                               const uint16_t* src,
+                                               const uint16_t* dest,
+                                               libvpx_test::MD5* md5_digest) {
+  if (use_fixed_values) {
+    // For fixed values, input and output are identical.
+    const bool success =
+        test_utils::CompareBlocks(src, dest, param_.width, param_.height,
+                                  kMaxBlockWidth, kMaxBlockWidth, false);
+    EXPECT_TRUE(success);
+  } else {
+    // For random input, compare md5.
+    const int offset =
+        kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+    const size_t size = sizeof(dest_16bit_) - offset * sizeof(uint16_t);
+    md5_digest->Add(reinterpret_cast<const uint8_t*>(dest), size);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveTest<bitdepth, Pixel>::Test(
+    bool use_fixed_values, int value, int num_runs /*= kMinimumViableRuns*/) {
+  // There's no meaning testing fixed input in compound convolve.
+  if (type_param_.is_compound && use_fixed_values) return;
+
+  // There should not be any function set for this combination.
+  if (type_param_.is_intra_block_copy && type_param_.is_compound) {
+    ASSERT_EQ(cur_convolve_func_, nullptr);
+    return;
+  }
+
+  // Compound and intra block copy functions are only used for blocks 4x4 or
+  // greater.
+  if (type_param_.is_compound || type_param_.is_intra_block_copy) {
+    if (param_.width < 4 || param_.height < 4) {
+      GTEST_SKIP();
+    }
+  }
+
+  // Skip unspecialized functions.
+  if (cur_convolve_func_ == nullptr) {
+    GTEST_SKIP();
+  }
+
+  SetInputData(use_fixed_values, value);
+  int subpixel_x = 0;
+  int subpixel_y = 0;
+  int vertical_index = 0;
+  int horizontal_index = 0;
+  const int offset =
+      kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+  const Pixel* const src = source_ + offset;
+  const ptrdiff_t src_stride = source_stride_ * sizeof(Pixel);
+  const ptrdiff_t src_stride_16 = source_stride_;
+  const ptrdiff_t dst_stride = kMaxBlockWidth * sizeof(Pixel);
+  // Pack Compound output since we control the predictor buffer.
+  const ptrdiff_t dst_stride_compound = param_.width;
+
+  // Output is always 16 bits regardless of |bitdepth|.
+  uint16_t* dst_16 = dest_16bit_ + offset;
+  // Output depends on |bitdepth|.
+  Pixel* dst_pixel = dest_clipped_ + offset;
+
+  // Collect the first |kMinimumViableRuns| into one md5 buffer.
+  libvpx_test::MD5 md5_digest;
+
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_runs; ++i) {
+    // Test every filter.
+    // Because of masking |subpixel_{x,y}| values roll over every 16 iterations.
+    subpixel_x += 1 << 6;
+    subpixel_y += 1 << 6;
+
+    const int horizontal_filter_id = (subpixel_x >> 6) & 0xF;
+    const int vertical_filter_id = (subpixel_y >> 6) & 0xF;
+
+    // |filter_id| == 0 (copy) must be handled by the appropriate 1D or copy
+    // function.
+    if (horizontal_filter_id == 0 || vertical_filter_id == 0) {
+      continue;
+    }
+
+    // For focused speed testing these can be set to the desired filter. Want
+    // only 8 tap filters? Set |{vertical,horizontal}_index| to 2.
+    vertical_index += static_cast<int>(i % 16 == 0);
+    vertical_index %= 4;
+    horizontal_index += static_cast<int>(i % 16 == 0);
+    horizontal_index %= 4;
+
+    if (type_param_.is_compound) {
+      // Output type is uint16_t.
+      const absl::Time start = absl::Now();
+      cur_convolve_func_(src, src_stride, horizontal_index, vertical_index,
+                         horizontal_filter_id, vertical_filter_id, param_.width,
+                         param_.height, dst_16, dst_stride_compound);
+      elapsed_time += absl::Now() - start;
+    } else {
+      // Output type is Pixel.
+      const absl::Time start = absl::Now();
+      cur_convolve_func_(src, src_stride, horizontal_index, vertical_index,
+                         horizontal_filter_id, vertical_filter_id, param_.width,
+                         param_.height, dst_pixel, dst_stride);
+      elapsed_time += absl::Now() - start;
+    }
+
+    // Only check the output for the first set. After that it's just repeated
+    // runs for speed timing.
+    if (i >= kMinimumViableRuns) continue;
+
+    if (type_param_.is_compound) {
+      // Need to copy source to a uint16_t buffer for comparison.
+      Pixel* src_ptr = source_;
+      uint16_t* src_ptr_16 = source_16bit_;
+      for (int y = 0; y < kMaxBlockHeight; ++y) {
+        for (int x = 0; x < kMaxBlockWidth; ++x) {
+          src_ptr_16[x] = src_ptr[x];
+        }
+        src_ptr += src_stride_16;
+        src_ptr_16 += src_stride_16;
+      }
+
+      Check16Bit(use_fixed_values, source_16bit_ + offset, dst_16, &md5_digest);
+    } else {
+      Check(use_fixed_values, src, dst_pixel, &md5_digest);
+    }
+  }
+
+  if (!use_fixed_values) {
+    // md5 sums are only calculated for random input.
+    const char* ref_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        ref_digest = GetConvolveDigest8bpp(GetDigestId());
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        ref_digest = GetConvolveDigest10bpp(GetDigestId());
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        ref_digest = GetConvolveDigest12bpp(GetDigestId());
+        break;
+#endif
+    }
+    ASSERT_NE(ref_digest, nullptr);
+
+    const char* direction;
+    if (type_param_.has_vertical_filter && type_param_.has_horizontal_filter) {
+      direction = "2D";
+    } else if (type_param_.has_vertical_filter) {
+      direction = "Vertical";
+    } else if (type_param_.has_horizontal_filter) {
+      direction = "Horizontal";
+    } else {
+      direction = "Copy";
+    }
+    const auto elapsed_time_us =
+        static_cast<int>(absl::ToInt64Microseconds(elapsed_time));
+    printf("Mode Convolve%s%s%s[%25s]: %5d us MD5: %s\n",
+           type_param_.is_compound ? "Compound" : "",
+           type_param_.is_intra_block_copy ? "IntraBlockCopy" : "", direction,
+           absl::StrFormat("%dx%d", param_.width, param_.height).c_str(),
+           elapsed_time_us, md5_digest.Get());
+    EXPECT_STREQ(ref_digest, md5_digest.Get());
+  }
+}
+
+void ApplyFilterToSignedInput(const int min_input, const int max_input,
+                              const int8_t filter[kSubPixelTaps],
+                              int* min_output, int* max_output) {
+  int min = 0, max = 0;
+  for (int i = 0; i < kSubPixelTaps; ++i) {
+    const int tap = filter[i];
+    if (tap > 0) {
+      max += max_input * tap;
+      min += min_input * tap;
+    } else {
+      min += max_input * tap;
+      max += min_input * tap;
+    }
+  }
+  *min_output = min;
+  *max_output = max;
+}
+
+void ApplyFilterToUnsignedInput(const int max_input,
+                                const int8_t filter[kSubPixelTaps],
+                                int* min_output, int* max_output) {
+  ApplyFilterToSignedInput(0, max_input, filter, min_output, max_output);
+}
+
+// Validate the maximum ranges for different parts of the Convolve process.
+template <int bitdepth>
+void ShowRange() {
+  // Subtract one from the shift bits because the filter is pre-shifted by 1.
+  constexpr int horizontal_bits = (bitdepth == kBitdepth12)
+                                      ? kInterRoundBitsHorizontal12bpp - 1
+                                      : kInterRoundBitsHorizontal - 1;
+  constexpr int vertical_bits = (bitdepth == kBitdepth12)
+                                    ? kInterRoundBitsVertical12bpp - 1
+                                    : kInterRoundBitsVertical - 1;
+  constexpr int compound_vertical_bits = kInterRoundBitsCompoundVertical - 1;
+
+  constexpr int compound_offset = (bitdepth == 8) ? 0 : kCompoundOffset;
+
+  constexpr int max_input = (1 << bitdepth) - 1;
+
+  const int8_t* worst_convolve_filter = kHalfSubPixelFilters[2][8];
+
+  // First pass.
+  printf("Bitdepth: %2d Input range:            [%8d, %8d]\n", bitdepth, 0,
+         max_input);
+
+  int min, max;
+  ApplyFilterToUnsignedInput(max_input, worst_convolve_filter, &min, &max);
+
+  if (bitdepth == 8) {
+    // 8bpp can use int16_t for sums.
+    assert(min > INT16_MIN);
+    assert(max < INT16_MAX);
+  } else {
+    // 10bpp and 12bpp require int32_t.
+    assert(min > INT32_MIN);
+    assert(max > INT16_MAX && max < INT32_MAX);
+  }
+
+  printf("  Horizontal upscaled range:         [%8d, %8d]\n", min, max);
+
+  const int first_pass_min = RightShiftWithRounding(min, horizontal_bits);
+  const int first_pass_max = RightShiftWithRounding(max, horizontal_bits);
+
+  // All bitdepths can use int16_t for first pass output.
+  assert(first_pass_min > INT16_MIN);
+  assert(first_pass_max < INT16_MAX);
+
+  printf("  Horizontal downscaled range:       [%8d, %8d]\n", first_pass_min,
+         first_pass_max);
+
+  // Second pass.
+  ApplyFilterToSignedInput(first_pass_min, first_pass_max,
+                           worst_convolve_filter, &min, &max);
+
+  // All bitdepths require int32_t for second pass sums.
+  assert(min < INT16_MIN && min > INT32_MIN);
+  assert(max > INT16_MAX && max < INT32_MAX);
+
+  printf("  Vertical upscaled range:           [%8d, %8d]\n", min, max);
+
+  // Second pass non-compound output is clipped to Pixel values.
+  const int second_pass_min =
+      Clip3(RightShiftWithRounding(min, vertical_bits), 0, max_input);
+  const int second_pass_max =
+      Clip3(RightShiftWithRounding(max, vertical_bits), 0, max_input);
+  printf("  Pixel output range:                [%8d, %8d]\n", second_pass_min,
+         second_pass_max);
+
+  // Output is Pixel so matches Pixel values.
+  assert(second_pass_min == 0);
+  assert(second_pass_max == max_input);
+
+  const int compound_second_pass_min =
+      RightShiftWithRounding(min, compound_vertical_bits) + compound_offset;
+  const int compound_second_pass_max =
+      RightShiftWithRounding(max, compound_vertical_bits) + compound_offset;
+
+  printf("  Compound output range:             [%8d, %8d]\n",
+         compound_second_pass_min, compound_second_pass_max);
+
+  if (bitdepth == 8) {
+    // 8bpp output is int16_t without an offset.
+    assert(compound_second_pass_min > INT16_MIN);
+    assert(compound_second_pass_max < INT16_MAX);
+  } else {
+    // 10bpp and 12bpp use the offset to fit inside uint16_t.
+    assert(compound_second_pass_min > 0);
+    assert(compound_second_pass_max < UINT16_MAX);
+  }
+
+  printf("\n");
+}
+
+TEST(ConvolveTest, ShowRange) {
+  ShowRange<kBitdepth8>();
+  ShowRange<kBitdepth10>();
+  ShowRange<kBitdepth12>();
+}
+
+using ConvolveTest8bpp = ConvolveTest<8, uint8_t>;
+
+TEST_P(ConvolveTest8bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, 255);
+}
+
+TEST_P(ConvolveTest8bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveTest8bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+//------------------------------------------------------------------------------
+template <int bitdepth, typename Pixel>
+class ConvolveScaleTest
+    : public testing::TestWithParam<
+          std::tuple<bool /*is_compound*/, ConvolveTestParam>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  ConvolveScaleTest() = default;
+  ~ConvolveScaleTest() override = default;
+
+  void SetUp() override {
+    ConvolveInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_convolve_scale_func_ = dsp->convolve_scale[is_compound_];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_convolve_scale_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        ConvolveInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        ConvolveInit_AVX2();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      ConvolveInit_NEON();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      ConvolveInit10bpp_NEON();
+#endif
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    cur_convolve_scale_func_ = dsp->convolve_scale[is_compound_];
+
+    // Skip functions that have not been specialized for this particular
+    // architecture.
+    if (cur_convolve_scale_func_ == base_convolve_scale_func_) {
+      cur_convolve_scale_func_ = nullptr;
+    }
+  }
+
+ protected:
+  int GetDigestId() const {
+    return param_.block_size +
+           param_.kNumBlockSizes * static_cast<int>(is_compound_);
+  }
+
+  void SetInputData(bool use_fixed_values, int value);
+  void Check(bool use_fixed_values, const Pixel* src, const Pixel* dest,
+             libvpx_test::MD5* md5_digest);
+  void Check16Bit(bool use_fixed_values, const uint16_t* src,
+                  const uint16_t* dest, libvpx_test::MD5* md5_digest);
+  // |num_runs| covers the categories of filters (6) and the number of filters
+  // under each category (16).
+  void Test(bool use_fixed_values, int value,
+            int num_runs = kMinimumViableRuns);
+
+  const bool is_compound_ = std::get<0>(GetParam());
+  const ConvolveTestParam param_ = std::get<1>(GetParam());
+
+ private:
+  ConvolveScaleFunc base_convolve_scale_func_;
+  ConvolveScaleFunc cur_convolve_scale_func_;
+  // Convolve filters are 7-tap, which need 3 pixels
+  // (kRestorationHorizontalBorder) padding.
+  // The source can be at most 2 times of max width/height.
+  Pixel source_[kMaxBlockHeight * kMaxBlockWidth * 4] = {};
+  uint16_t source_16bit_[kMaxBlockHeight * kMaxBlockWidth * 4] = {};
+  uint16_t dest_16bit_[kMaxBlockHeight * kMaxBlockWidth] = {};
+  Pixel dest_clipped_[kMaxBlockHeight * kMaxBlockWidth] = {};
+
+  const int source_stride_ = kMaxBlockWidth * 2;
+  const int source_height_ = kMaxBlockHeight * 2;
+};
+
+template <int bitdepth, typename Pixel>
+void ConvolveScaleTest<bitdepth, Pixel>::SetInputData(bool use_fixed_values,
+                                                      int value) {
+  if (use_fixed_values) {
+    std::fill(source_, source_ + source_height_ * source_stride_, value);
+  } else {
+    const int offset =
+        kConvolveBorderLeftTop * source_stride_ + kConvolveBorderLeftTop;
+    const int mask = (1 << bitdepth) - 1;
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    const int height = param_.height * 2;
+    const int width = param_.width * 2;
+    for (int y = 0; y < height; ++y) {
+      for (int x = 0; x < width; ++x) {
+        source_[y * source_stride_ + x + offset] = rnd.Rand16() & mask;
+      }
+    }
+    // Copy border pixels to the left and right borders.
+    for (int y = 0; y < height; ++y) {
+      Memset(&source_[(y + kConvolveBorderLeftTop) * source_stride_],
+             source_[y * source_stride_ + offset], kConvolveBorderLeftTop);
+      Memset(&source_[y * source_stride_ + offset + width],
+             source_[y * source_stride_ + offset + width - 1],
+             kConvolveBorderLeftTop);
+    }
+    // Copy border pixels to the top and bottom borders.
+    for (int y = 0; y < kConvolveBorderLeftTop; ++y) {
+      memcpy(&source_[y * source_stride_],
+             &source_[kConvolveBorderLeftTop * source_stride_],
+             source_stride_ * sizeof(Pixel));
+      memcpy(&source_[(y + kConvolveBorderLeftTop + height) * source_stride_],
+             &source_[(kConvolveBorderLeftTop + height - 1) * source_stride_],
+             source_stride_ * sizeof(Pixel));
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveScaleTest<bitdepth, Pixel>::Check(bool use_fixed_values,
+                                               const Pixel* src,
+                                               const Pixel* dest,
+                                               libvpx_test::MD5* md5_digest) {
+  if (use_fixed_values) {
+    // For fixed values, input and output are identical.
+    const bool success =
+        test_utils::CompareBlocks(src, dest, param_.width, param_.height,
+                                  kMaxBlockWidth, kMaxBlockWidth, false, false);
+    EXPECT_TRUE(success);
+  } else {
+    // For random input, compare md5.
+    const int offset =
+        kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+    const size_t size = sizeof(dest_clipped_) - offset * sizeof(Pixel);
+    md5_digest->Add(reinterpret_cast<const uint8_t*>(dest), size);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveScaleTest<bitdepth, Pixel>::Check16Bit(
+    bool use_fixed_values, const uint16_t* src, const uint16_t* dest,
+    libvpx_test::MD5* md5_digest) {
+  if (use_fixed_values) {
+    // For fixed values, input and output are identical.
+    const bool success =
+        test_utils::CompareBlocks(src, dest, param_.width, param_.height,
+                                  kMaxBlockWidth, kMaxBlockWidth, false);
+    EXPECT_TRUE(success);
+  } else {
+    // For random input, compare md5.
+    const int offset =
+        kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+    const size_t size = sizeof(dest_16bit_) - offset * sizeof(uint16_t);
+    md5_digest->Add(reinterpret_cast<const uint8_t*>(dest), size);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ConvolveScaleTest<bitdepth, Pixel>::Test(
+    bool use_fixed_values, int value, int num_runs /*= kMinimumViableRuns*/) {
+  // There's no meaning testing fixed input in compound convolve.
+  if (is_compound_ && use_fixed_values) return;
+
+  // The compound function is only used for blocks 4x4 or greater.
+  if (is_compound_) {
+    if (param_.width < 4 || param_.height < 4) {
+      GTEST_SKIP();
+    }
+  }
+
+  // Skip unspecialized functions.
+  if (cur_convolve_scale_func_ == nullptr) {
+    GTEST_SKIP();
+  }
+
+  SetInputData(use_fixed_values, value);
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed() +
+                             GetDigestId());
+  // [1,2048] for |step_[xy]|. This covers a scaling range of 1/1024 to 2x.
+  const int step_x = (rnd.Rand16() & ((1 << 11) - 1)) + 1;
+  const int step_y = (rnd.Rand16() & ((1 << 11) - 1)) + 1;
+  int subpixel_x = 0;
+  int subpixel_y = 0;
+  int vertical_index = 0;
+  int horizontal_index = 0;
+  const int offset =
+      kConvolveBorderLeftTop * kMaxBlockWidth + kConvolveBorderLeftTop;
+  const int offset_scale =
+      kConvolveBorderLeftTop * source_stride_ + kConvolveBorderLeftTop;
+  const Pixel* const src_scale = source_ + offset_scale;
+  const ptrdiff_t src_stride = source_stride_ * sizeof(Pixel);
+  const ptrdiff_t dst_stride = kMaxBlockWidth * sizeof(Pixel);
+  // Pack Compound output since we control the predictor buffer.
+  const ptrdiff_t dst_stride_compound = param_.width;
+
+  // Output is always 16 bits regardless of |bitdepth|.
+  uint16_t* dst_16 = dest_16bit_ + offset;
+  // Output depends on |bitdepth|.
+  Pixel* dst_pixel = dest_clipped_ + offset;
+
+  // Collect the first |kMinimumViableRuns| into one md5 buffer.
+  libvpx_test::MD5 md5_digest;
+
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_runs; ++i) {
+    // Test every filter.
+    // Because of masking |subpixel_{x,y}| values roll over every 16 iterations.
+    subpixel_x += 1 << 6;
+    subpixel_y += 1 << 6;
+
+    const int horizontal_filter_id = (subpixel_x >> 6) & 0xF;
+    const int vertical_filter_id = (subpixel_y >> 6) & 0xF;
+
+    // |filter_id| == 0 (copy) must be handled by the appropriate 1D or copy
+    // function.
+    if (horizontal_filter_id == 0 || vertical_filter_id == 0) {
+      continue;
+    }
+
+    // For focused speed testing these can be set to the desired filter. Want
+    // only 8 tap filters? Set |{vertical,horizontal}_index| to 2.
+    vertical_index += static_cast<int>(i % 16 == 0);
+    vertical_index %= 4;
+    horizontal_index += static_cast<int>(i % 16 == 0);
+    horizontal_index %= 4;
+
+    // Output type is uint16_t.
+    const absl::Time start = absl::Now();
+    if (is_compound_) {
+      cur_convolve_scale_func_(
+          source_, src_stride, horizontal_index, vertical_index, 0, 0, step_x,
+          step_y, param_.width, param_.height, dst_16, dst_stride_compound);
+    } else {
+      cur_convolve_scale_func_(
+          source_, src_stride, horizontal_index, vertical_index, 0, 0, step_x,
+          step_y, param_.width, param_.height, dst_pixel, dst_stride);
+    }
+    elapsed_time += absl::Now() - start;
+
+    // Only check the output for the first set. After that it's just repeated
+    // runs for speed timing.
+    if (i >= kMinimumViableRuns) continue;
+
+    // Convolve function does not clip the output. The clipping is applied
+    // later, but libaom clips the output. So we apply clipping to match
+    // libaom in tests.
+    if (is_compound_) {
+      const int single_round_offset = (1 << bitdepth) + (1 << (bitdepth - 1));
+      Pixel* dest_row = dest_clipped_;
+      for (int y = 0; y < kMaxBlockHeight; ++y) {
+        for (int x = 0; x < kMaxBlockWidth; ++x) {
+          dest_row[x] = static_cast<Pixel>(Clip3(
+              dest_16bit_[y * dst_stride_compound + x] - single_round_offset, 0,
+              (1 << bitdepth) - 1));
+        }
+        dest_row += kMaxBlockWidth;
+      }
+    }
+
+    if (is_compound_) {
+      Check16Bit(use_fixed_values, source_16bit_ + offset_scale, dst_16,
+                 &md5_digest);
+    } else {
+      Check(use_fixed_values, src_scale, dst_pixel, &md5_digest);
+    }
+  }
+
+  if (!use_fixed_values) {
+    // md5 sums are only calculated for random input.
+    const char* ref_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        ref_digest = GetConvolveScaleDigest8bpp(GetDigestId());
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        ref_digest = GetConvolveScaleDigest10bpp(GetDigestId());
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        ref_digest = GetConvolveScaleDigest12bpp(GetDigestId());
+        break;
+#endif
+    }
+    ASSERT_NE(ref_digest, nullptr);
+
+    const auto elapsed_time_us =
+        static_cast<int>(absl::ToInt64Microseconds(elapsed_time));
+    printf("Mode Convolve%sScale2D[%25s]: %5d us MD5: %s\n",
+           is_compound_ ? "Compound" : "",
+           absl::StrFormat("%dx%d", param_.width, param_.height).c_str(),
+           elapsed_time_us, md5_digest.Get());
+    EXPECT_STREQ(ref_digest, md5_digest.Get());
+  }
+}
+
+using ConvolveScaleTest8bpp = ConvolveScaleTest<8, uint8_t>;
+
+TEST_P(ConvolveScaleTest8bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, 255);
+}
+
+TEST_P(ConvolveScaleTest8bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveScaleTest8bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+//------------------------------------------------------------------------------
+const ConvolveTestParam kConvolveParam[] = {
+    ConvolveTestParam(ConvolveTestParam::kBlockSize2x2),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize2x4),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize4x2),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize4x4),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize4x8),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize8x2),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize8x4),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize8x8),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize8x16),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize16x8),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize16x16),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize16x32),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize32x16),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize32x32),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize32x64),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize64x32),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize64x64),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize64x128),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize128x64),
+    ConvolveTestParam(ConvolveTestParam::kBlockSize128x128),
+};
+
+const ConvolveTypeParam kConvolveTypeParam[] = {
+    ConvolveTypeParam(false, false, false, false),
+    ConvolveTypeParam(false, false, false, true),
+    ConvolveTypeParam(false, false, true, false),
+    ConvolveTypeParam(false, false, true, true),
+    ConvolveTypeParam(false, true, false, false),
+    ConvolveTypeParam(false, true, false, true),
+    ConvolveTypeParam(false, true, true, false),
+    ConvolveTypeParam(false, true, true, true),
+    ConvolveTypeParam(true, false, false, false),
+    ConvolveTypeParam(true, false, false, true),
+    ConvolveTypeParam(true, false, true, false),
+    ConvolveTypeParam(true, false, true, true),
+    // This is left to ensure no function exists for |intra_block_copy| when
+    // |is_compound| is true; all combinations aren't necessary.
+    ConvolveTypeParam(true, true, false, false),
+};
+
+INSTANTIATE_TEST_SUITE_P(C, ConvolveTest8bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(C, ConvolveScaleTest8bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ConvolveTest8bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(NEON, ConvolveScaleTest8bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, ConvolveTest8bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(SSE41, ConvolveScaleTest8bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveTest8bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveScaleTest8bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+#endif  // LIBGAV1_ENABLE_AVX2
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using ConvolveTest10bpp = ConvolveTest<10, uint16_t>;
+
+TEST_P(ConvolveTest10bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, (1 << 10) - 1);
+}
+
+TEST_P(ConvolveTest10bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveTest10bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+using ConvolveScaleTest10bpp = ConvolveScaleTest<10, uint16_t>;
+
+TEST_P(ConvolveScaleTest10bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, (1 << 10) - 1);
+}
+
+TEST_P(ConvolveScaleTest10bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveScaleTest10bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, ConvolveTest10bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(C, ConvolveScaleTest10bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ConvolveTest10bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(NEON, ConvolveScaleTest10bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using ConvolveTest12bpp = ConvolveTest<12, uint16_t>;
+
+TEST_P(ConvolveTest12bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, (1 << 12) - 1);
+}
+
+TEST_P(ConvolveTest12bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveTest12bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+using ConvolveScaleTest12bpp = ConvolveScaleTest<12, uint16_t>;
+
+TEST_P(ConvolveScaleTest12bpp, FixedValues) {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, (1 << 12) - 1);
+}
+
+TEST_P(ConvolveScaleTest12bpp, RandomValues) { Test(false, 0); }
+
+TEST_P(ConvolveScaleTest12bpp, DISABLED_Speed) {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, ConvolveTest12bpp,
+                         testing::Combine(testing::ValuesIn(kConvolveTypeParam),
+                                          testing::ValuesIn(kConvolveParam)));
+INSTANTIATE_TEST_SUITE_P(C, ConvolveScaleTest12bpp,
+                         testing::Combine(testing::Bool(),
+                                          testing::ValuesIn(kConvolveParam)));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/distance_weighted_blend_test.cc b/src/dsp/distance_weighted_blend_test.cc
new file mode 100644
index 0000000..88040b4
--- /dev/null
+++ b/src/dsp/distance_weighted_blend_test.cc
@@ -0,0 +1,329 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/distance_weighted_blend.h"
+
+#include <cassert>
+#include <cstdint>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kNumSpeedTests = 500000;
+
+constexpr int kQuantizedDistanceLookup[4][2] = {
+    {9, 7}, {11, 5}, {12, 4}, {13, 3}};
+
+template <int bitdepth, typename Pixel>
+class DistanceWeightedBlendTest : public testing::TestWithParam<BlockSize>,
+                                  public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  DistanceWeightedBlendTest() = default;
+  ~DistanceWeightedBlendTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    DistanceWeightedBlendInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_func_ = dsp->distance_weighted_blend;
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        DistanceWeightedBlendInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      DistanceWeightedBlendInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    func_ = dsp->distance_weighted_blend;
+  }
+
+ protected:
+  void Test(const char* digest, int num_tests);
+
+ private:
+  using PredType =
+      typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
+  static constexpr int kDestStride = kMaxSuperBlockSizeInPixels;
+  const int width_ = kBlockWidthPixels[GetParam()];
+  const int height_ = kBlockHeightPixels[GetParam()];
+  alignas(kMaxAlignment) PredType
+      source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
+  alignas(kMaxAlignment) PredType
+      source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
+  Pixel dest_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
+  Pixel reference_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] =
+      {};
+  dsp::DistanceWeightedBlendFunc base_func_;
+  dsp::DistanceWeightedBlendFunc func_;
+};
+
+template <int bitdepth, typename Pixel>
+void DistanceWeightedBlendTest<bitdepth, Pixel>::Test(const char* digest,
+                                                      int num_tests) {
+  if (func_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  PredType* src_1 = source1_;
+  PredType* src_2 = source2_;
+
+  const int index = rnd.Rand8() & 3;
+  const uint8_t weight_0 = kQuantizedDistanceLookup[index][0];
+  const uint8_t weight_1 = kQuantizedDistanceLookup[index][1];
+  // In libgav1, predictors have an offset which are later subtracted and
+  // clipped in distance weighted blending. Therefore we add the offset
+  // here to match libaom's implementation.
+  for (int y = 0; y < height_; ++y) {
+    for (int x = 0; x < width_; ++x) {
+      // distance_weighted_blend is applied to compound prediction values. This
+      // implies a range far exceeding that of pixel values.
+      // The ranges include kCompoundOffset in 10bpp and 12bpp.
+      // see: src/dsp/convolve.cc & src/dsp/warp.cc.
+      static constexpr int kCompoundPredictionRange[3][2] = {
+          // 8bpp
+          {-5132, 9212},
+          // 10bpp
+          {3988, 61532},
+          // 12bpp
+          {3974, 61559},
+      };
+      constexpr int bitdepth_index = (bitdepth - 8) >> 1;
+      const int min_val = kCompoundPredictionRange[bitdepth_index][0];
+      const int max_val = kCompoundPredictionRange[bitdepth_index][1];
+      src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+      src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+    }
+    src_1 += width_;
+    src_2 += width_;
+  }
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_tests; ++i) {
+    const absl::Time start = absl::Now();
+    func_(source1_, source2_, weight_0, weight_1, width_, height_, dest_,
+          sizeof(Pixel) * kDestStride);
+    elapsed_time += absl::Now() - start;
+  }
+
+  test_utils::CheckMd5Digest("DistanceWeightedBlend", ToString(GetParam()),
+                             digest, dest_, sizeof(dest_), elapsed_time);
+}
+
+const BlockSize kTestParam[] = {
+    kBlock4x4,    kBlock4x8,     kBlock4x16,  kBlock8x4,   kBlock8x8,
+    kBlock8x16,   kBlock8x32,    kBlock16x4,  kBlock16x8,  kBlock16x16,
+    kBlock16x32,  kBlock16x64,   kBlock32x8,  kBlock32x16, kBlock32x32,
+    kBlock32x64,  kBlock64x16,   kBlock64x32, kBlock64x64, kBlock64x128,
+    kBlock128x64, kBlock128x128,
+};
+
+const char* GetDistanceWeightedBlendDigest8bpp(const BlockSize block_size) {
+  static const char* const kDigests[kMaxBlockSizes] = {
+      // 4xN
+      "ebf389f724f8ab46a2cac895e4e073ca",
+      "09acd567b6b12c8cf8eb51d8b86eb4bf",
+      "57bb4d65695d8ec6752f2bd8686b64fd",
+      // 8xN
+      "270905ac76f9a2cba8a552eb0bf7c8c1",
+      "f0801c8574d2c271ef2bbea77a1d7352",
+      "e761b580e3312be33a227492a233ce72",
+      "ff214dab1a7e98e2285961d6421720c6",
+      // 16xN
+      "4f712609a36e817f9752326d58562ff8",
+      "14243f5c5f7c7104160c1f2cef0a0fbc",
+      "3ac3f3161b7c8dd8436b02abfdde104a",
+      "81a00b704e0e41a5dbe6436ac70c098d",
+      "af8fd02017c7acdff788be742d700baa",
+      // 32xN
+      "ee34332c66a6d6ed8ce64031aafe776c",
+      "b5e3d22bd2dbdb624c8b86a1afb5ce6d",
+      "607ffc22098d81b7e37a7bf62f4af5d3",
+      "3823dbf043b4682f56d5ca698e755ea5",
+      // 64xN
+      "4acf556b921956c2bc24659cd5128401",
+      "a298c544c9c3b27924b4c23cc687ea5a",
+      "539e2df267782ce61c70103b23b7d922",
+      "3b0cb2a0b5d384efee4d81401025bec1",
+      // 128xN
+      "8b56b636dd712c2f8d138badb7219991",
+      "8cfc8836908902b8f915639b7bff45b3",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+using DistanceWeightedBlendTest8bpp = DistanceWeightedBlendTest<8, uint8_t>;
+
+TEST_P(DistanceWeightedBlendTest8bpp, Blending) {
+  Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), 1);
+}
+
+TEST_P(DistanceWeightedBlendTest8bpp, DISABLED_Speed) {
+  Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest8bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDistanceWeightedBlendDigest10bpp(const BlockSize block_size) {
+  static const char* const kDigests[] = {
+      // 4xN
+      "55f594b56e16d5c401274affebbcc3d3",
+      "69df14da4bb33a8f7d7087921008e919",
+      "1b61f33604c54015794198a13bfebf46",
+      // 8xN
+      "825a938185b152f7cf09bf1c0723ce2b",
+      "85ea315c51d979bc9b45834d6b40ec6f",
+      "92ebde208e8c39f7ec6de2de82182dbb",
+      "520f84716db5b43684dbb703806383fe",
+      // 16xN
+      "12ca23e3e2930005a0511646e8c83da4",
+      "6208694a6744f4a3906f58c1add670e3",
+      "a33d63889df989a3bbf84ff236614267",
+      "34830846ecb0572a98bbd192fed02b16",
+      "34bb2f79c0bd7f9a80691b8af597f2a8",
+      // 32xN
+      "fa97f2d0e3143f1f44d3ac018b0d696d",
+      "3df4a22456c9ab6ed346ab1b9750ae7d",
+      "6276a058b35c6131bc0c94a4b4a37ebc",
+      "9ca42da5d2d5eb339df03ae2c7a26914",
+      // 64xN
+      "800e692c520f99223bc24c1ac95a0166",
+      "818b6d20426585ef7fe844015a03aaf5",
+      "fb48691ccfff083e01d74826e88e613f",
+      "0bd350bc5bc604a224d77a5f5a422698",
+      // 128xN
+      "a130840813cd6bd69d09bcf5f8d0180f",
+      "6ece1846bea55e8f8f2ed7fbf73718de",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+using DistanceWeightedBlendTest10bpp = DistanceWeightedBlendTest<10, uint16_t>;
+
+TEST_P(DistanceWeightedBlendTest10bpp, Blending) {
+  Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), 1);
+}
+
+TEST_P(DistanceWeightedBlendTest10bpp, DISABLED_Speed) {
+  Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest10bpp,
+                         testing::ValuesIn(kTestParam));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDistanceWeightedBlendDigest12bpp(const BlockSize block_size) {
+  static const char* const kDigests[] = {
+      // 4xN
+      "e30bf8f5f294206ad1dd79bd10a20827",
+      "f0cfb60134562d9c5f2ec6ad106e01ef",
+      "ad0876244e1b769203266a9c75b74afc",
+      // 8xN
+      "5265b954479c15a80f427561c5f36ff4",
+      "7f157457d1671e4ecce7a0884e9e3f76",
+      "d2cef5cf217f2d1f787c8951b7fe7cb2",
+      "6d23059008adbbb84ac941c8b4968f5b",
+      // 16xN
+      "ae521a5656ed3440d1fa950c20d90a79",
+      "935bec0e12b5dd3e0c34b3de8ba51476",
+      "0334bafcdcd7ddddb673ded492bca25a",
+      "c5360f08d0be77c79dc19fb55a0c5fe0",
+      "c2d1e7a4244a8aaaac041aed0cefc148",
+      // 32xN
+      "ce7f3cf78ae4f836cf69763137f7f6a6",
+      "800e52ebb14d5831c047d391cd760f95",
+      "74aa2b412b42165f1967daf3042b4f17",
+      "140d4cc600944b629b1991e88a9fe97c",
+      // 64xN
+      "3d206f93229ee2cea5c5da4e0ac6445a",
+      "3d13028f8fffe79fd35752c0177291ca",
+      "e7a7669acb5979dc7b15a19eed09cd4c",
+      "599368f4971c203fc5fa32989fe8cb44",
+      // 128xN
+      "54b46af2e2c8d2081e26fa0315b4ffd7",
+      "602e769bb2104e78223e68e50e7e86a0",
+  };
+  assert(block_size < kMaxBlockSizes);
+  return kDigests[block_size];
+}
+
+using DistanceWeightedBlendTest12bpp = DistanceWeightedBlendTest<12, uint16_t>;
+
+TEST_P(DistanceWeightedBlendTest12bpp, Blending) {
+  Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), 1);
+}
+
+TEST_P(DistanceWeightedBlendTest12bpp, DISABLED_Speed) {
+  Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest12bpp,
+                         testing::ValuesIn(kTestParam));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const BlockSize param) {
+  return os << ToString(param);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/dsp_test.cc b/src/dsp/dsp_test.cc
new file mode 100644
index 0000000..6d2817b
--- /dev/null
+++ b/src/dsp/dsp_test.cc
@@ -0,0 +1,272 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/dsp.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/strings/str_cat.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+
+#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
+#include "tests/utils.h"
+#endif
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// Maps 1D transform to the maximum valid size for the corresponding transform.
+constexpr int kMaxTransform1dSize[kNumTransform1ds] = {
+    kTransform1dSize64,  // Dct.
+    kTransform1dSize16,  // Adst.
+    kTransform1dSize32,  // Identity.
+    kTransform1dSize4,   // Wht.
+};
+
+void CheckTables(bool c_only) {
+#if LIBGAV1_MAX_BITDEPTH == 12
+  static constexpr int kBitdepths[] = {kBitdepth8, kBitdepth10, kBitdepth12};
+#elif LIBGAV1_MAX_BITDEPTH >= 10
+  static constexpr int kBitdepths[] = {kBitdepth8, kBitdepth10};
+#else
+  static constexpr int kBitdepths[] = {kBitdepth8};
+#endif
+
+  for (const auto& bitdepth : kBitdepths) {
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    SCOPED_TRACE(absl::StrCat("bitdepth: ", bitdepth));
+    for (int i = 0; i < kNumTransformSizes; ++i) {
+      for (int j = 0; j < kNumIntraPredictors; ++j) {
+        EXPECT_NE(dsp->intra_predictors[i][j], nullptr)
+            << "index [" << i << "][" << j << "]";
+      }
+    }
+    EXPECT_NE(dsp->directional_intra_predictor_zone1, nullptr);
+    EXPECT_NE(dsp->directional_intra_predictor_zone2, nullptr);
+    EXPECT_NE(dsp->directional_intra_predictor_zone3, nullptr);
+    EXPECT_NE(dsp->filter_intra_predictor, nullptr);
+    for (int i = 0; i < kNumTransformSizes; ++i) {
+      if (std::max(kTransformWidth[i], kTransformHeight[i]) == 64) {
+        EXPECT_EQ(dsp->cfl_intra_predictors[i], nullptr)
+            << "index [" << i << "]";
+        for (int j = 0; j < kNumSubsamplingTypes; ++j) {
+          EXPECT_EQ(dsp->cfl_subsamplers[i][j], nullptr)
+              << "index [" << i << "][" << j << "]";
+        }
+      } else {
+        EXPECT_NE(dsp->cfl_intra_predictors[i], nullptr)
+            << "index [" << i << "]";
+        for (int j = 0; j < kNumSubsamplingTypes; ++j) {
+          EXPECT_NE(dsp->cfl_subsamplers[i][j], nullptr)
+              << "index [" << i << "][" << j << "]";
+        }
+      }
+    }
+    EXPECT_NE(dsp->intra_edge_filter, nullptr);
+    EXPECT_NE(dsp->intra_edge_upsampler, nullptr);
+    for (int i = 0; i < kNumTransform1ds; ++i) {
+      for (int j = 0; j < kNumTransform1dSizes; ++j) {
+        for (int k = 0; k < 2; ++k) {
+          if (j <= kMaxTransform1dSize[i]) {
+            EXPECT_NE(dsp->inverse_transforms[i][j][k], nullptr)
+                << "index [" << i << "][" << j << "][" << k << "]";
+          } else {
+            EXPECT_EQ(dsp->inverse_transforms[i][j][k], nullptr)
+                << "index [" << i << "][" << j << "][" << k << "]";
+          }
+        }
+      }
+    }
+    for (int i = 0; i < kNumLoopFilterSizes; ++i) {
+      for (int j = 0; j < kNumLoopFilterTypes; ++j) {
+        EXPECT_NE(dsp->loop_filters[i][j], nullptr)
+            << "index [" << i << "][" << j << "]";
+      }
+    }
+    for (int i = 0; i < 2; ++i) {
+      EXPECT_NE(dsp->loop_restorations[i], nullptr) << "index [" << i << "]";
+    }
+
+    bool super_res_coefficients_is_nonnull = LIBGAV1_ENABLE_NEON;
+#if LIBGAV1_ENABLE_SSE4_1
+    const uint32_t cpu_features = GetCpuInfo();
+    super_res_coefficients_is_nonnull = (cpu_features & kSSE4_1) != 0;
+#endif
+    if (c_only || bitdepth == kBitdepth12) {
+      super_res_coefficients_is_nonnull = false;
+    }
+    if (super_res_coefficients_is_nonnull) {
+      EXPECT_NE(dsp->super_res_coefficients, nullptr);
+    } else {
+      EXPECT_EQ(dsp->super_res_coefficients, nullptr);
+    }
+
+    EXPECT_NE(dsp->super_res, nullptr);
+    EXPECT_NE(dsp->cdef_direction, nullptr);
+    for (int i = 0; i < 2; ++i) {
+      for (int j = 0; j < 3; ++j) {
+        EXPECT_NE(dsp->cdef_filters[i][j], nullptr)
+            << "index [" << i << "][" << j << "]";
+      }
+    }
+    for (auto convolve_func : dsp->convolve_scale) {
+      EXPECT_NE(convolve_func, nullptr);
+    }
+    for (int j = 0; j < 2; ++j) {
+      for (int k = 0; k < 2; ++k) {
+        for (int l = 0; l < 2; ++l) {
+          for (int m = 0; m < 2; ++m) {
+            if (j == 1 && k == 1) {
+              EXPECT_EQ(dsp->convolve[j][k][l][m], nullptr);
+            } else {
+              EXPECT_NE(dsp->convolve[j][k][l][m], nullptr);
+            }
+          }
+        }
+      }
+    }
+    for (const auto& m : dsp->mask_blend) {
+      for (int i = 0; i < 2; ++i) {
+        if (i == 0 || bitdepth >= 10) {
+          EXPECT_NE(m[i], nullptr);
+        } else {
+          EXPECT_EQ(m[i], nullptr);
+        }
+      }
+    }
+    for (const auto& m : dsp->inter_intra_mask_blend_8bpp) {
+      if (bitdepth == 8) {
+        EXPECT_NE(m, nullptr);
+      } else {
+        EXPECT_EQ(m, nullptr);
+      }
+    }
+    for (int i = kBlock4x4; i < kMaxBlockSizes; ++i) {
+      const int width_index = k4x4WidthLog2[i] - 1;
+      const int height_index = k4x4HeightLog2[i] - 1;
+      // Only block sizes >= 8x8 are handled with this function.
+      if (width_index < 0 || height_index < 0) continue;
+
+      for (size_t j = 0; j < 2; ++j) {
+        EXPECT_NE(dsp->weight_mask[width_index][height_index][j], nullptr)
+            << ToString(static_cast<BlockSize>(i)) << " index [" << width_index
+            << "]"
+            << "[" << height_index << "][" << j << "]";
+      }
+    }
+
+    EXPECT_NE(dsp->average_blend, nullptr);
+    EXPECT_NE(dsp->distance_weighted_blend, nullptr);
+    for (int i = 0; i < kNumObmcDirections; ++i) {
+      EXPECT_NE(dsp->obmc_blend[i], nullptr)
+          << "index [" << ToString(static_cast<ObmcDirection>(i)) << "]";
+    }
+    EXPECT_NE(dsp->warp, nullptr);
+    EXPECT_NE(dsp->warp_compound, nullptr);
+
+    for (int i = 0; i < kNumAutoRegressionLags - 1; ++i) {
+      EXPECT_NE(dsp->film_grain.luma_auto_regression[i], nullptr)
+          << "index [" << i << "]";
+    }
+    for (int i = 0; i < 2; ++i) {
+      for (int j = 0; j < kNumAutoRegressionLags; ++j) {
+        if (i == 0 && j == 0) {
+          EXPECT_EQ(dsp->film_grain.chroma_auto_regression[i][j], nullptr)
+              << " index [" << i << "]"
+              << "[" << j << "]";
+        } else {
+          EXPECT_NE(dsp->film_grain.chroma_auto_regression[i][j], nullptr)
+              << " index [" << i << "]"
+              << "[" << j << "]";
+        }
+      }
+      EXPECT_NE(dsp->film_grain.construct_noise_stripes[i], nullptr)
+          << "index [" << i << "]";
+      EXPECT_NE(dsp->film_grain.blend_noise_chroma[i], nullptr)
+          << "index [" << i << "]";
+    }
+    EXPECT_NE(dsp->film_grain.construct_noise_image_overlap, nullptr);
+    EXPECT_NE(dsp->film_grain.initialize_scaling_lut, nullptr);
+    EXPECT_NE(dsp->film_grain.blend_noise_luma, nullptr);
+
+    if (bitdepth == 8) {
+      EXPECT_NE(dsp->motion_field_projection_kernel, nullptr);
+      EXPECT_NE(dsp->mv_projection_compound[0], nullptr);
+      EXPECT_NE(dsp->mv_projection_compound[1], nullptr);
+      EXPECT_NE(dsp->mv_projection_compound[2], nullptr);
+      EXPECT_NE(dsp->mv_projection_single[0], nullptr);
+      EXPECT_NE(dsp->mv_projection_single[1], nullptr);
+      EXPECT_NE(dsp->mv_projection_single[2], nullptr);
+    } else {
+      EXPECT_EQ(dsp->motion_field_projection_kernel, nullptr);
+      EXPECT_EQ(dsp->mv_projection_compound[0], nullptr);
+      EXPECT_EQ(dsp->mv_projection_compound[1], nullptr);
+      EXPECT_EQ(dsp->mv_projection_compound[2], nullptr);
+      EXPECT_EQ(dsp->mv_projection_single[0], nullptr);
+      EXPECT_EQ(dsp->mv_projection_single[1], nullptr);
+      EXPECT_EQ(dsp->mv_projection_single[2], nullptr);
+    }
+  }
+}
+
+TEST(Dsp, TablesArePopulated) {
+  DspInit();
+  CheckTables(/*c_only=*/false);
+}
+
+#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
+TEST(Dsp, TablesArePopulatedCOnly) {
+  test_utils::ResetDspTable(kBitdepth8);
+#if LIBGAV1_MAX_BITDEPTH >= 10
+  test_utils::ResetDspTable(kBitdepth10);
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+  test_utils::ResetDspTable(kBitdepth12);
+#endif
+  dsp_internal::DspInit_C();
+  CheckTables(/*c_only=*/true);
+}
+#endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
+
+TEST(Dsp, GetDspTable) {
+  EXPECT_EQ(GetDspTable(1), nullptr);
+  EXPECT_NE(GetDspTable(kBitdepth8), nullptr);
+  EXPECT_EQ(dsp_internal::GetWritableDspTable(1), nullptr);
+  EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth8), nullptr);
+#if LIBGAV1_MAX_BITDEPTH >= 10
+  EXPECT_NE(GetDspTable(kBitdepth10), nullptr);
+  EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth10), nullptr);
+#else
+  EXPECT_EQ(GetDspTable(kBitdepth10), nullptr);
+  EXPECT_EQ(dsp_internal::GetWritableDspTable(kBitdepth10), nullptr);
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+  EXPECT_NE(GetDspTable(kBitdepth12), nullptr);
+  EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth12), nullptr);
+#else
+  EXPECT_EQ(GetDspTable(kBitdepth12), nullptr);
+  EXPECT_EQ(dsp_internal::GetWritableDspTable(kBitdepth12), nullptr);
+#endif
+}
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/intra_edge_test.cc b/src/dsp/intra_edge_test.cc
new file mode 100644
index 0000000..b287544
--- /dev/null
+++ b/src/dsp/intra_edge_test.cc
@@ -0,0 +1,558 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/intra_edge.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+const char kIntraEdge[] = "IntraEdge";
+const char kIntraEdgeFilterName[] = "Intra Edge Filter";
+const char kIntraEdgeUpsamplerName[] = "Intra Edge Upsampler";
+
+constexpr int kIntraEdgeBufferSize = 144;  // see Tile::IntraPrediction.
+constexpr int kIntraEdgeFilterTestMaxSize = 129;
+constexpr int kIntraEdgeFilterTestFixedInput[kIntraEdgeFilterTestMaxSize] = {
+    159, 208, 54,  136, 205, 124, 125, 165, 164, 63,  171, 143, 210, 236, 253,
+    233, 139, 113, 66,  211, 133, 61,  91,  123, 187, 76,  110, 172, 61,  103,
+    239, 147, 247, 120, 18,  106, 180, 159, 208, 54,  136, 205, 124, 125, 165,
+    164, 63,  171, 143, 210, 236, 253, 233, 139, 113, 66,  211, 133, 61,  91,
+    123, 187, 76,  110, 172, 61,  103, 239, 147, 247, 120, 18,  106, 180, 159,
+    208, 54,  136, 205, 124, 125, 165, 164, 63,  171, 143, 210, 236, 253, 233,
+    139, 113, 66,  211, 133, 61,  91,  123, 187, 76,  110, 172, 61,  103, 239,
+    147, 247, 120, 18,  106, 180, 159, 208, 54,  136, 205, 124, 125, 165, 164,
+    63,  171, 143, 210, 236, 253, 233, 139, 113,
+};
+constexpr int kIntraEdgeUpsamplerTestFixedInput[] = {
+    208, 54,  136, 205, 124, 125, 165, 164, 63,
+    171, 143, 210, 236, 208, 54,  136, 205};
+
+struct EdgeFilterParams {
+  int size;
+  int strength;
+};
+
+std::ostream& operator<<(std::ostream& os, const EdgeFilterParams& param) {
+  return os << "size: " << param.size << ", strength: " << param.strength;
+}
+
+// Each size is paired with strength 1, 2, and 3.
+// In general, the size is expressible as 2^n+1, but all sizes up to 129 are
+// permissible.
+constexpr EdgeFilterParams kIntraEdgeFilterParamList[] = {
+    {1, 1},  {1, 2},  {1, 3},  {2, 1},   {2, 2},   {2, 3},  {5, 1},  {5, 2},
+    {5, 3},  {9, 1},  {9, 2},  {9, 3},   {17, 1},  {17, 2}, {17, 3}, {33, 1},
+    {33, 2}, {33, 3}, {50, 1}, {50, 2},  {50, 3},  {55, 1}, {55, 2}, {55, 3},
+    {65, 1}, {65, 2}, {65, 3}, {129, 1}, {129, 2}, {129, 3}};
+
+template <int bitdepth, typename Pixel>
+class IntraEdgeFilterTest : public testing::TestWithParam<EdgeFilterParams> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraEdgeFilterTest() = default;
+  IntraEdgeFilterTest(const IntraEdgeFilterTest&) = delete;
+  IntraEdgeFilterTest& operator=(const IntraEdgeFilterTest&) = delete;
+  ~IntraEdgeFilterTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    IntraEdgeInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_intra_edge_filter_ = dsp->intra_edge_filter;
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_intra_edge_filter_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraEdgeInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraEdgeInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+#if LIBGAV1_MSAN
+    // Match the behavior of Tile::IntraPrediction to prevent warnings due to
+    // assembly code (safely) overreading to fill a register.
+    memset(buffer_, 0, sizeof(buffer_));
+#endif  // LIBGAV1_MSAN
+    cur_intra_edge_filter_ = dsp->intra_edge_filter;
+  }
+
+  void TestFixedValues(const char* digest);
+  void TestRandomValues(int num_runs);
+
+  Pixel buffer_[kIntraEdgeBufferSize];
+  Pixel base_buffer_[kIntraEdgeBufferSize];
+  int strength_ = GetParam().strength;
+  int size_ = GetParam().size;
+
+  IntraEdgeFilterFunc base_intra_edge_filter_;
+  IntraEdgeFilterFunc cur_intra_edge_filter_;
+};
+
+template <int bitdepth, typename Pixel>
+void IntraEdgeFilterTest<bitdepth, Pixel>::TestFixedValues(
+    const char* const digest) {
+  if (cur_intra_edge_filter_ == nullptr) return;
+  for (int i = 0; i < kIntraEdgeFilterTestMaxSize; ++i) {
+    buffer_[i] = kIntraEdgeFilterTestFixedInput[i];
+  }
+  const absl::Time start = absl::Now();
+  cur_intra_edge_filter_(buffer_, size_, strength_);
+  const absl::Duration elapsed_time = absl::Now() - start;
+  test_utils::CheckMd5Digest(kIntraEdge, kIntraEdgeFilterName, digest, buffer_,
+                             kIntraEdgeFilterTestMaxSize * sizeof(buffer_[0]),
+                             elapsed_time);
+}
+
+template <int bitdepth, typename Pixel>
+void IntraEdgeFilterTest<bitdepth, Pixel>::TestRandomValues(int num_runs) {
+  if (base_intra_edge_filter_ == nullptr) return;
+  if (cur_intra_edge_filter_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  absl::Duration elapsed_time;
+  absl::Duration base_elapsed_time;
+  memset(base_buffer_, 0, sizeof(base_buffer_));
+  memset(buffer_, 0, sizeof(buffer_));
+  for (int num_tests = 0; num_tests < num_runs; ++num_tests) {
+    for (int i = 0; i < size_; ++i) {
+      const Pixel val = rnd(1 << bitdepth);
+      buffer_[i] = val;
+      base_buffer_[i] = val;
+    }
+    const absl::Time base_start = absl::Now();
+    base_intra_edge_filter_(base_buffer_, size_, strength_);
+    base_elapsed_time += absl::Now() - base_start;
+    const absl::Time start = absl::Now();
+    cur_intra_edge_filter_(buffer_, size_, strength_);
+    elapsed_time += absl::Now() - start;
+  }
+  if (num_runs > 1) {
+    printf("Mode %s[%31s] Size %3d Strength %d C: %5d us SIMD: %5d us %2.2fx\n",
+           kIntraEdge, kIntraEdgeFilterName, size_, strength_,
+           static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time)),
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)),
+           absl::ToDoubleMicroseconds(base_elapsed_time) /
+               absl::ToDoubleMicroseconds(elapsed_time));
+  } else {
+    printf("Mode %s[%31s] Size %3d Strength %d\n", kIntraEdge,
+           kIntraEdgeFilterName, size_, strength_);
+  }
+  for (int i = 0; i < kIntraEdgeFilterTestMaxSize; ++i) {
+    EXPECT_EQ(buffer_[i], base_buffer_[i]) << "Mismatch in index: " << i;
+  }
+}
+
+using IntraEdgeFilterTest8bpp = IntraEdgeFilterTest<8, uint8_t>;
+
+const char* GetIntraEdgeFilterDigest8bpp(int strength, int size) {
+  static const char* const kDigestsSize1[3] = {
+      "f7f681cf7047602fafc7fb416ecf46e1", "f7f681cf7047602fafc7fb416ecf46e1",
+      "f7f681cf7047602fafc7fb416ecf46e1"};
+  static const char* const kDigestsSize2[3] = {
+      "cb24cc54900fb75d767f3de797451e43", "380c80c89e1e8cda81ee0d3d4b29b8b7",
+      "a7eb3dba95ff35c2df45a274afbc9772"};
+  static const char* const kDigestsSize5[3] = {
+      "23380cb37688d4c3a8f70a276be65eed", "ec1e23d5b996a527ed3d45c0d552bf22",
+      "d313523d3b7646fdbb873c61ffe7a51a"};
+  static const char* const kDigestsSize9[3] = {
+      "e79597e9d62893754fc77d80ca86329a", "f7644e9748984914100e7031c6432272",
+      "bdf4f16734c86338716fb436c196ecc6"};
+  static const char* const kDigestsSize17[3] = {
+      "13ad15c833e850348eecb9fea4f3cadb", "e5988a72391250c702a8192893df40dd",
+      "8f68603598638fa33203fe1233d273b1"};
+  static const char* const kDigestsSize33[3] = {
+      "51156da8f4d527e0c011040769987dbd", "eff17eaf73a7bb7fd4c921510ade9f67",
+      "aca87680e0649d0728091c92c6de8871"};
+  static const char* const kDigestsSize50[3] = {
+      "87c1d43751125f1ea4987517a90d378d", "942a9d056231683bdfc52346b6b032c2",
+      "16a9148daf0e5f69808b9f0caa1ef110"};
+  static const char* const kDigestsSize55[3] = {
+      "833480d74957fb0356dec5b09412eefa", "a307ef31f10affc3b7fb262d05f1b80a",
+      "0318b2fde088c472215fe155f3b48d36"};
+  static const char* const kDigestsSize65[3] = {
+      "5000dada34ed2e6692bb44a4398ddf53", "8da6c776d897064ecd4a1e84aae92dd3",
+      "d7c71db339c28d33119974987b2f9d85"};
+  static const char* const kDigestsSize129[3] = {
+      "bf174d8b45b8131404fd4a4686f8c117", "e81518d6d85eed2f1b18c59424561d6b",
+      "7306715602b0f5536771724a2f0a39bc"};
+
+  switch (size) {
+    case 1:
+      return kDigestsSize1[strength - 1];
+    case 2:
+      return kDigestsSize2[strength - 1];
+    case 5:
+      return kDigestsSize5[strength - 1];
+    case 9:
+      return kDigestsSize9[strength - 1];
+    case 17:
+      return kDigestsSize17[strength - 1];
+    case 33:
+      return kDigestsSize33[strength - 1];
+    case 50:
+      return kDigestsSize50[strength - 1];
+    case 55:
+      return kDigestsSize55[strength - 1];
+    case 65:
+      return kDigestsSize65[strength - 1];
+    case 129:
+      return kDigestsSize129[strength - 1];
+    default:
+      ADD_FAILURE() << "Unknown edge size: " << size;
+      return nullptr;
+  }
+}
+
+TEST_P(IntraEdgeFilterTest8bpp, Correctness) {
+  TestFixedValues(GetIntraEdgeFilterDigest8bpp(strength_, size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeFilterTest8bpp, DISABLED_Speed) { TestRandomValues(1e7); }
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using IntraEdgeFilterTest10bpp = IntraEdgeFilterTest<10, uint16_t>;
+
+const char* GetIntraEdgeFilterDigest10bpp(int strength, int size) {
+  static const char* const kDigestsSize1[3] = {
+      "2d2088560e3ccb5b809c97f5299bb1c0", "2d2088560e3ccb5b809c97f5299bb1c0",
+      "2d2088560e3ccb5b809c97f5299bb1c0"};
+  static const char* const kDigestsSize2[3] = {
+      "db3e785852e98fba18a1fb531f68466c", "8caea330489bc6ed0f99fbf769f53181",
+      "bcdd1b21f3baf5f6f29caea9ef93fb0c"};
+  static const char* const kDigestsSize5[3] = {
+      "326f4193a62f5a959b86d95f5204608e", "4673e453203f75eae97ef44f43f098f2",
+      "48d516b06313683aca30e975ce6a3cad"};
+  static const char* const kDigestsSize9[3] = {
+      "79217575a32e36a51d9dd40621af9c2d", "ccec1c16bc09b28ad6513c5e4c48b6d2",
+      "bb61aa9c5fa720c667a053769e7b7d08"};
+  static const char* const kDigestsSize17[3] = {
+      "46d90e99ba46e89326a5fa547bcd9361", "824aee8950aecb356d5f4a91dbc90a7d",
+      "37d44d10a2545385af1da55f8c08564f"};
+  static const char* const kDigestsSize33[3] = {
+      "c95108e06eb2aef61ecb6839af306edd", "832c695460b4dd2b85c5f8726e4470d1",
+      "994902f549eefd83fbcbf7ecb7dc5cca"};
+  static const char* const kDigestsSize50[3] = {
+      "48119ef1436c3a4fe69d275bbaafedf8", "72c221c91c3df0a324ccbc9acea35f89",
+      "84e40aadcc416ef3f51cea3cc23b30c7"};
+  static const char* const kDigestsSize55[3] = {
+      "6b68e4e0b00c4eb38a6d0d83c0f34658", "43a919f928a80379df5c9e07c9d8000d",
+      "7c320d55b11f93185b811bdaa379f2db"};
+  static const char* const kDigestsSize65[3] = {
+      "c28de89cf9f3bc5a904647ab2c64caf7", "7ce63b1b28dce0624fc7586e8fb3ab8f",
+      "d06e6b88585f7f1a1f6af5bb59ee2180"};
+  static const char* const kDigestsSize129[3] = {
+      "79160902c5c85004382d5ffa549b43cc", "3b0df95c3ca7b0b559b79234cf434738",
+      "500786d8561effec283d4f3d13886f8c"};
+
+  switch (size) {
+    case 1:
+      return kDigestsSize1[strength - 1];
+    case 2:
+      return kDigestsSize2[strength - 1];
+    case 5:
+      return kDigestsSize5[strength - 1];
+    case 9:
+      return kDigestsSize9[strength - 1];
+    case 17:
+      return kDigestsSize17[strength - 1];
+    case 33:
+      return kDigestsSize33[strength - 1];
+    case 50:
+      return kDigestsSize50[strength - 1];
+    case 55:
+      return kDigestsSize55[strength - 1];
+    case 65:
+      return kDigestsSize65[strength - 1];
+    case 129:
+      return kDigestsSize129[strength - 1];
+    default:
+      ADD_FAILURE() << "Unknown edge size: " << size;
+      return nullptr;
+  }
+}
+
+TEST_P(IntraEdgeFilterTest10bpp, FixedInput) {
+  TestFixedValues(GetIntraEdgeFilterDigest10bpp(strength_, size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeFilterTest10bpp, DISABLED_Speed) { TestRandomValues(1e7); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using IntraEdgeFilterTest12bpp = IntraEdgeFilterTest<12, uint16_t>;
+
+const char* GetIntraEdgeFilterDigest12bpp(int strength, int size) {
+  return GetIntraEdgeFilterDigest10bpp(strength, size);
+}
+
+TEST_P(IntraEdgeFilterTest12bpp, FixedInput) {
+  TestFixedValues(GetIntraEdgeFilterDigest12bpp(strength_, size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeFilterTest12bpp, DISABLED_Speed) { TestRandomValues(1e7); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+template <int bitdepth, typename Pixel>
+class IntraEdgeUpsamplerTest : public testing::TestWithParam<int> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraEdgeUpsamplerTest() = default;
+  IntraEdgeUpsamplerTest(const IntraEdgeUpsamplerTest&) = delete;
+  IntraEdgeUpsamplerTest& operator=(const IntraEdgeUpsamplerTest&) = delete;
+  ~IntraEdgeUpsamplerTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    IntraEdgeInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_intra_edge_upsampler_ = dsp->intra_edge_upsampler;
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_intra_edge_upsampler_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraEdgeInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraEdgeInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    cur_intra_edge_upsampler_ = dsp->intra_edge_upsampler;
+#if LIBGAV1_MSAN
+    // Match the behavior of Tile::IntraPrediction to prevent warnings due to
+    // assembly code (safely) overreading to fill a register.
+    memset(buffer_, 0, sizeof(buffer_));
+#endif
+  }
+
+  void TestFixedValues(const char* digest);
+  void TestRandomValues(int num_runs);
+
+  Pixel buffer_[128];
+  Pixel base_buffer_[128];
+  int size_ = GetParam();
+
+  IntraEdgeUpsamplerFunc base_intra_edge_upsampler_;
+  IntraEdgeUpsamplerFunc cur_intra_edge_upsampler_;
+};
+
+template <int bitdepth, typename Pixel>
+void IntraEdgeUpsamplerTest<bitdepth, Pixel>::TestFixedValues(
+    const char* const digest) {
+  if (cur_intra_edge_upsampler_ == nullptr) return;
+  buffer_[0] = 0;
+  for (int i = 0; i < size_ + 1; ++i) {
+    buffer_[i + 1] = kIntraEdgeUpsamplerTestFixedInput[i];
+  }
+  const absl::Time start = absl::Now();
+  cur_intra_edge_upsampler_(buffer_ + 2, size_);
+  const absl::Duration elapsed_time = absl::Now() - start;
+  test_utils::CheckMd5Digest(kIntraEdge, kIntraEdgeUpsamplerName, digest,
+                             buffer_, (size_ * 2 + 1) * sizeof(buffer_[0]),
+                             elapsed_time);
+}
+
+template <int bitdepth, typename Pixel>
+void IntraEdgeUpsamplerTest<bitdepth, Pixel>::TestRandomValues(int num_runs) {
+  if (base_intra_edge_upsampler_ == nullptr) return;
+  if (cur_intra_edge_upsampler_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  absl::Duration base_elapsed_time;
+  absl::Duration elapsed_time;
+  for (int num_tests = 0; num_tests < num_runs; ++num_tests) {
+    // Populate what will be buffer[-2..size] when passed to the upsample
+    // function.
+    buffer_[0] = 0;
+    base_buffer_[0] = 0;
+    for (int i = 1; i < size_ + 2; ++i) {
+      const Pixel val = rnd(1 << bitdepth);
+      buffer_[i] = val;
+      base_buffer_[i] = val;
+    }
+    const absl::Time base_start = absl::Now();
+    base_intra_edge_upsampler_(base_buffer_ + 2, size_);
+    base_elapsed_time += absl::Now() - base_start;
+    const absl::Time start = absl::Now();
+    cur_intra_edge_upsampler_(buffer_ + 2, size_);
+    elapsed_time += absl::Now() - start;
+  }
+  if (num_runs > 1) {
+    printf("Mode %s[%31s] size %d C: %5d us SIMD: %5d us %2.2fx\n", kIntraEdge,
+           kIntraEdgeUpsamplerName, size_,
+           static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time)),
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)),
+           absl::ToDoubleMicroseconds(base_elapsed_time) /
+               absl::ToDoubleMicroseconds(elapsed_time));
+  } else {
+    printf("Mode %s[%31s]: size %d \n", kIntraEdge, kIntraEdgeUpsamplerName,
+           size_);
+  }
+
+  for (int i = 0; i < size_ * 2 + 1; ++i) {
+    EXPECT_EQ(buffer_[i], base_buffer_[i]) << "Mismatch in index: " << i;
+  }
+}
+
+using IntraEdgeUpsamplerTest8bpp = IntraEdgeUpsamplerTest<8, uint8_t>;
+
+constexpr int kIntraEdgeUpsampleSizes[] = {4, 8, 12, 16};
+
+const char* GetIntraEdgeUpsampleDigest8bpp(int size) {
+  switch (size) {
+    case 4:
+      return "aa9002e03f8d15eb26bbee76f40bb923";
+    case 8:
+      return "cacfca86d65eff0d951eb21fc15f242a";
+    case 12:
+      return "0529e00a1fa80bc866fa7662ad2d7b9f";
+    case 16:
+      return "03e3b3e0ea438ea48ef05651c0a54986";
+    default:
+      ADD_FAILURE() << "Unknown upsample size: " << size;
+      return "";
+  }
+}
+
+TEST_P(IntraEdgeUpsamplerTest8bpp, Correctness) {
+  TestFixedValues(GetIntraEdgeUpsampleDigest8bpp(size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeUpsamplerTest8bpp, DISABLED_Speed) { TestRandomValues(5e7); }
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using IntraEdgeUpsamplerTest10bpp = IntraEdgeUpsamplerTest<10, uint16_t>;
+
+const char* GetIntraEdgeUpsampleDigest10bpp(int size) {
+  switch (size) {
+    case 4:
+      return "341c6bb705a02bba65b34f92d8ca83cf";
+    case 8:
+      return "fdbe4b3b341921dcb0edf00dfc4d7667";
+    case 12:
+      return "ad69a491287495ec9973d4006d5ac461";
+    case 16:
+      return "04acf32e517d80ce4c4958e711b9b890";
+    default:
+      ADD_FAILURE() << "Unknown upsample size: " << size;
+      return "";
+  }
+}
+
+TEST_P(IntraEdgeUpsamplerTest10bpp, FixedInput) {
+  TestFixedValues(GetIntraEdgeUpsampleDigest10bpp(size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeUpsamplerTest10bpp, DISABLED_Speed) { TestRandomValues(5e7); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using IntraEdgeUpsamplerTest12bpp = IntraEdgeUpsamplerTest<12, uint16_t>;
+
+const char* GetIntraEdgeUpsampleDigest12bpp(int size) {
+  return GetIntraEdgeUpsampleDigest10bpp(size);
+}
+
+TEST_P(IntraEdgeUpsamplerTest12bpp, FixedInput) {
+  TestFixedValues(GetIntraEdgeUpsampleDigest12bpp(size_));
+  TestRandomValues(1);
+}
+
+TEST_P(IntraEdgeUpsamplerTest12bpp, DISABLED_Speed) { TestRandomValues(5e7); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeFilterTest8bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, IntraEdgeFilterTest8bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, IntraEdgeFilterTest8bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+#endif
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeUpsamplerTest8bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, IntraEdgeUpsamplerTest8bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, IntraEdgeUpsamplerTest8bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeFilterTest10bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeUpsamplerTest10bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, IntraEdgeFilterTest10bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+INSTANTIATE_TEST_SUITE_P(NEON, IntraEdgeUpsamplerTest10bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+#endif
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeFilterTest12bpp,
+                         testing::ValuesIn(kIntraEdgeFilterParamList));
+INSTANTIATE_TEST_SUITE_P(C, IntraEdgeUpsamplerTest12bpp,
+                         testing::ValuesIn(kIntraEdgeUpsampleSizes));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/intrapred_cfl_test.cc b/src/dsp/intrapred_cfl_test.cc
new file mode 100644
index 0000000..8415d51
--- /dev/null
+++ b/src/dsp/intrapred_cfl_test.cc
@@ -0,0 +1,1169 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/intrapred_cfl.h"
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockSize = 64;
+constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
+
+const char* const kCflIntraPredName = "kCflIntraPredictor";
+
+template <int bitdepth, typename Pixel>
+class IntraPredTestBase : public testing::TestWithParam<TransformSize>,
+                          public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraPredTestBase() {
+    switch (tx_size_) {
+      case kNumTransformSizes:
+        EXPECT_NE(tx_size_, kNumTransformSizes);
+        break;
+      default:
+        block_width_ = kTransformWidth[tx_size_];
+        block_height_ = kTransformHeight[tx_size_];
+        break;
+    }
+  }
+
+  IntraPredTestBase(const IntraPredTestBase&) = delete;
+  IntraPredTestBase& operator=(const IntraPredTestBase&) = delete;
+  ~IntraPredTestBase() override = default;
+
+ protected:
+  struct IntraPredMem {
+    void Reset(libvpx_test::ACMRandom* rnd) {
+      ASSERT_NE(rnd, nullptr);
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      const int mask = (1 << bitdepth) - 1;
+      for (auto& r : ref_src) r = rnd->Rand16() & mask;
+      for (int i = 0; i < kMaxBlockSize; ++i) left[i] = rnd->Rand16() & mask;
+      for (int i = -1; i < kMaxBlockSize; ++i) top[i] = rnd->Rand16() & mask;
+
+      // Some directional predictors require top-right, bottom-left.
+      for (int i = kMaxBlockSize; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = rnd->Rand16() & mask;
+        top[i] = rnd->Rand16() & mask;
+      }
+      // TODO(jzern): reorder this and regenerate the digests after switching
+      // random number generators.
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      left[-1] = rnd->Rand16() & mask;
+      left[-2] = rnd->Rand16() & mask;
+      top[-2] = rnd->Rand16() & mask;
+      memset(left_mem, 0, sizeof(left_mem[0]) * 14);
+      memset(top_mem, 0, sizeof(top_mem[0]) * 14);
+      memset(top_mem + kMaxBlockSize * 2 + 16, 0,
+             sizeof(top_mem[0]) * kTopMemPadding);
+    }
+
+    // Set ref_src, top-left, top and left to |pixel|.
+    void Set(const Pixel pixel) {
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      for (auto& r : ref_src) r = pixel;
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      for (int i = -2; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = top[i] = pixel;
+      }
+    }
+
+    // DirectionalZone1_Large() overreads up to 7 pixels in |top_mem|.
+    static constexpr int kTopMemPadding = 7;
+    alignas(kMaxAlignment) Pixel dst[kTotalPixels];
+    alignas(kMaxAlignment) Pixel ref_src[kTotalPixels];
+    alignas(kMaxAlignment) Pixel left_mem[kMaxBlockSize * 2 + 16];
+    alignas(
+        kMaxAlignment) Pixel top_mem[kMaxBlockSize * 2 + 16 + kTopMemPadding];
+  };
+
+  void SetUp() override { test_utils::ResetDspTable(bitdepth); }
+
+  const TransformSize tx_size_ = GetParam();
+  int block_width_;
+  int block_height_;
+  IntraPredMem intra_pred_mem_;
+};
+
+//------------------------------------------------------------------------------
+// CflIntraPredTest
+
+template <int bitdepth, typename Pixel>
+class CflIntraPredTest : public IntraPredTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  CflIntraPredTest() = default;
+  CflIntraPredTest(const CflIntraPredTest&) = delete;
+  CflIntraPredTest& operator=(const CflIntraPredTest&) = delete;
+  ~CflIntraPredTest() override = default;
+
+ protected:
+  using IntraPredTestBase<bitdepth, Pixel>::tx_size_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_width_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_height_;
+  using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_;
+
+  void SetUp() override {
+    IntraPredTestBase<bitdepth, Pixel>::SetUp();
+    IntraPredCflInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_cfl_intra_pred_ = dsp->cfl_intra_predictors[tx_size_];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_cfl_intra_pred_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraPredCflInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraPredCflInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    cur_cfl_intra_pred_ = dsp->cfl_intra_predictors[tx_size_];
+
+    if (cur_cfl_intra_pred_ == base_cfl_intra_pred_) {
+      cur_cfl_intra_pred_ = nullptr;
+    }
+  }
+
+  // This test modifies intra_pred_mem_.
+  void TestSpeed(const char* digest, int num_runs);
+  void TestSaturatedValues();
+  void TestRandomValues();
+
+  CflIntraPredictorFunc base_cfl_intra_pred_;
+  CflIntraPredictorFunc cur_cfl_intra_pred_;
+};
+
+template <int bitdepth, typename Pixel>
+void CflIntraPredTest<bitdepth, Pixel>::TestSpeed(const char* const digest,
+                                                  const int num_runs) {
+  if (cur_cfl_intra_pred_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  int16_t luma[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+  const int alpha = rnd(33) - 16;
+  const int dc = rnd(1 << bitdepth);
+  const int max_luma = ((1 << bitdepth) - 1) << 3;
+  for (int i = 0; i < block_height_; ++i) {
+    for (int j = 0; j < block_width_; ++j) {
+      if (i < kCflLumaBufferStride && j < kCflLumaBufferStride) {
+        luma[i][j] = max_luma - rnd(max_luma << 1);
+      }
+    }
+  }
+  for (auto& r : intra_pred_mem_.ref_src) r = dc;
+
+  absl::Duration elapsed_time;
+  for (int run = 0; run < num_runs; ++run) {
+    const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const absl::Time start = absl::Now();
+    cur_cfl_intra_pred_(intra_pred_mem_.dst, stride, luma, alpha);
+    elapsed_time += absl::Now() - start;
+  }
+  test_utils::CheckMd5Digest(ToString(tx_size_), kCflIntraPredName, digest,
+                             intra_pred_mem_.dst, sizeof(intra_pred_mem_.dst),
+                             elapsed_time);
+}
+
+template <int bitdepth, typename Pixel>
+void CflIntraPredTest<bitdepth, Pixel>::TestSaturatedValues() {
+  // Skip the 'C' test case as this is used as the reference.
+  if (base_cfl_intra_pred_ == nullptr) return;
+
+  int16_t luma_buffer[kCflLumaBufferStride][kCflLumaBufferStride];
+  for (auto& line : luma_buffer) {
+    for (auto& luma : line) luma = ((1 << bitdepth) - 1) << 3;
+  }
+
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  static constexpr int kSaturatedAlpha[] = {-16, 16};
+  for (const int alpha : kSaturatedAlpha) {
+    for (auto& r : intra_pred_mem_.ref_src) r = (1 << bitdepth) - 1;
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+    base_cfl_intra_pred_(intra_pred_mem_.ref_src, stride, luma_buffer, alpha);
+    cur_cfl_intra_pred_(intra_pred_mem_.dst, stride, luma_buffer, alpha);
+    if (!test_utils::CompareBlocks(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                                   block_width_, block_height_, kMaxBlockSize,
+                                   kMaxBlockSize, true)) {
+      ADD_FAILURE() << "Result from optimized version of CFL with alpha "
+                    << alpha << " differs from reference.";
+      break;
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void CflIntraPredTest<bitdepth, Pixel>::TestRandomValues() {
+  // Skip the 'C' test case as this is used as the reference.
+  if (base_cfl_intra_pred_ == nullptr) return;
+  int16_t luma_buffer[kCflLumaBufferStride][kCflLumaBufferStride];
+
+  const int max_luma = ((1 << bitdepth) - 1) << 3;
+  // Use an alternate seed to differentiate this test from TestSpeed().
+  libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed);
+  for (auto& line : luma_buffer) {
+    for (auto& luma : line) luma = max_luma - rnd(max_luma << 1);
+  }
+  const int dc = rnd(1 << bitdepth);
+  for (auto& r : intra_pred_mem_.ref_src) r = dc;
+  static constexpr int kSaturatedAlpha[] = {-16, 16};
+  for (const int alpha : kSaturatedAlpha) {
+    intra_pred_mem_.Reset(&rnd);
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+    base_cfl_intra_pred_(intra_pred_mem_.ref_src, stride, luma_buffer, alpha);
+    cur_cfl_intra_pred_(intra_pred_mem_.dst, stride, luma_buffer, alpha);
+    if (!test_utils::CompareBlocks(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                                   block_width_, block_height_, kMaxBlockSize,
+                                   kMaxBlockSize, true)) {
+      ADD_FAILURE() << "Result from optimized version of CFL with alpha "
+                    << alpha << " differs from reference.";
+      break;
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel, SubsamplingType subsampling_type>
+class CflSubsamplerTest : public IntraPredTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  CflSubsamplerTest() = default;
+  CflSubsamplerTest(const CflSubsamplerTest&) = delete;
+  CflSubsamplerTest& operator=(const CflSubsamplerTest&) = delete;
+  ~CflSubsamplerTest() override = default;
+
+ protected:
+  using IntraPredTestBase<bitdepth, Pixel>::tx_size_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_width_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_height_;
+  using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_;
+
+  void SetUp() override {
+    IntraPredTestBase<bitdepth, Pixel>::SetUp();
+    IntraPredCflInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_cfl_subsampler_ = dsp->cfl_subsamplers[tx_size_][subsampling_type];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_cfl_subsampler_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraPredCflInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraPredCflInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    cur_cfl_subsampler_ = dsp->cfl_subsamplers[tx_size_][subsampling_type];
+  }
+
+  // This test modifies intra_pred_mem_.
+  void TestSpeed(const char* digest, int num_runs);
+  void TestSaturatedValues();
+  void TestRandomValues();
+
+  enum SubsamplingType SubsamplingType() const { return subsampling_type; }
+
+  CflSubsamplerFunc base_cfl_subsampler_;
+  CflSubsamplerFunc cur_cfl_subsampler_;
+};
+
+// There is no case where both source and output have lowest height or width
+// when that dimension is subsampled.
+int GetLumaWidth(int block_width, SubsamplingType subsampling_type) {
+  if (block_width == 4) {
+    const int width_shift =
+        static_cast<int>(subsampling_type != kSubsamplingType444);
+    return block_width << width_shift;
+  }
+  return block_width;
+}
+
+int GetLumaHeight(int block_height, SubsamplingType subsampling_type) {
+  if (block_height == 4) {
+    const int height_shift =
+        static_cast<int>(subsampling_type == kSubsamplingType420);
+    return block_height << height_shift;
+  }
+  return block_height;
+}
+
+template <int bitdepth, typename Pixel, SubsamplingType subsampling_type>
+void CflSubsamplerTest<bitdepth, Pixel, subsampling_type>::TestSpeed(
+    const char* const digest, const int num_runs) {
+  // C declines initializing the table in normal circumstances because there are
+  // assembly implementations.
+  if (cur_cfl_subsampler_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+
+  const int width = GetLumaWidth(block_width_, subsampling_type);
+  const int height = GetLumaHeight(block_height_, subsampling_type);
+  Pixel* src = intra_pred_mem_.ref_src;
+#if LIBGAV1_MSAN
+  // Quiet 10bpp CflSubsampler420_NEON() msan warning.
+  memset(src, 0, sizeof(intra_pred_mem_.ref_src));
+#endif
+  for (int i = 0; i < height; ++i) {
+    for (int j = 0; j < width; ++j) {
+      src[j] = rnd.RandRange(1 << bitdepth);
+    }
+    src += kMaxBlockSize;
+  }
+  const absl::Time start = absl::Now();
+  int16_t luma[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+  const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+  for (int run = 0; run < num_runs; ++run) {
+    cur_cfl_subsampler_(luma, width, height, intra_pred_mem_.ref_src, stride);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  test_utils::CheckMd5Digest(ToString(tx_size_), kCflIntraPredName, digest,
+                             luma, sizeof(luma), elapsed_time);
+}
+
+template <int bitdepth, typename Pixel, SubsamplingType subsampling_type>
+void CflSubsamplerTest<bitdepth, Pixel,
+                       subsampling_type>::TestSaturatedValues() {
+  if (base_cfl_subsampler_ == nullptr) return;
+  const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+  for (int width = GetLumaWidth(block_width_, subsampling_type); width > 0;
+       width -= 8) {
+    for (int height = GetLumaHeight(block_height_, subsampling_type);
+         height > 0; height -= 8) {
+      Pixel* src = intra_pred_mem_.ref_src;
+      for (int y = 0; y < height; ++y) {
+        Memset(src, (1 << bitdepth) - 1, width);
+        Memset(src + width, 0, kMaxBlockSize - width);
+        src += kMaxBlockSize;
+      }
+      Memset(intra_pred_mem_.ref_src + kMaxBlockSize * height, 0,
+             kMaxBlockSize * (kMaxBlockSize - height));
+
+      int16_t luma_base[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+      int16_t luma_cur[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+      base_cfl_subsampler_(luma_base, width, height, intra_pred_mem_.ref_src,
+                           stride);
+      cur_cfl_subsampler_(luma_cur, width, height, intra_pred_mem_.ref_src,
+                          stride);
+      if (!test_utils::CompareBlocks(reinterpret_cast<uint16_t*>(luma_cur[0]),
+                                     reinterpret_cast<uint16_t*>(luma_base[0]),
+                                     block_width_, block_height_,
+                                     kCflLumaBufferStride, kCflLumaBufferStride,
+                                     true)) {
+        FAIL() << "Result from optimized version of CFL subsampler"
+               << " differs from reference. max_luma_width: " << width
+               << " max_luma_height: " << height;
+      }
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel, SubsamplingType subsampling_type>
+void CflSubsamplerTest<bitdepth, Pixel, subsampling_type>::TestRandomValues() {
+  if (base_cfl_subsampler_ == nullptr) return;
+  const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+  // Use an alternate seed to differentiate this test from TestSpeed().
+  libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed);
+  for (int width = GetLumaWidth(block_width_, subsampling_type); width > 0;
+       width -= 8) {
+    for (int height = GetLumaHeight(block_height_, subsampling_type);
+         height > 0; height -= 8) {
+      Pixel* src = intra_pred_mem_.ref_src;
+      for (int i = 0; i < height; ++i) {
+        for (int j = 0; j < width; ++j) {
+          src[j] = rnd.RandRange(1 << bitdepth);
+        }
+        Memset(src + width, 0, kMaxBlockSize - width);
+        src += kMaxBlockSize;
+      }
+      Memset(intra_pred_mem_.ref_src + kMaxBlockSize * height, 0,
+             kMaxBlockSize * (kMaxBlockSize - height));
+
+      int16_t luma_base[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+      int16_t luma_cur[kCflLumaBufferStride][kCflLumaBufferStride] = {};
+      base_cfl_subsampler_(luma_base, width, height, intra_pred_mem_.ref_src,
+                           stride);
+      cur_cfl_subsampler_(luma_cur, width, height, intra_pred_mem_.ref_src,
+                          stride);
+      if (!test_utils::CompareBlocks(reinterpret_cast<uint16_t*>(luma_cur[0]),
+                                     reinterpret_cast<uint16_t*>(luma_base[0]),
+                                     block_width_, block_height_,
+                                     kCflLumaBufferStride, kCflLumaBufferStride,
+                                     true)) {
+        FAIL() << "Result from optimized version of CFL subsampler"
+               << " differs from reference. max_luma_width: " << width
+               << " max_luma_height: " << height;
+      }
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+
+using CflIntraPredTest8bpp = CflIntraPredTest<8, uint8_t>;
+
+const char* GetCflIntraPredDigest8bpp(TransformSize tx_size) {
+  static const char* const kDigest4x4 = "9ea7088e082867fd5ae394ca549fe1ed";
+  static const char* const kDigest4x8 = "323b0b4784b6658da781398e61f2da3d";
+  static const char* const kDigest4x16 = "99eb9c65f227ca7f71dcac24645a4fec";
+  static const char* const kDigest8x4 = "e8e782e31c94f3974b87b93d455262d8";
+  static const char* const kDigest8x8 = "23ab9fb65e7bbbdb985709e115115eb5";
+  static const char* const kDigest8x16 = "52f5add2fc4bbb2ff893148645e95b9c";
+  static const char* const kDigest8x32 = "283fdee9af8afdb76f72dd7339c92c3c";
+  static const char* const kDigest16x4 = "eead35f515b1aa8b5175b283192b86e6";
+  static const char* const kDigest16x8 = "5778e934254eaab04230bc370f64f778";
+  static const char* const kDigest16x16 = "4e8ed38ccba0d62f1213171da2212ed3";
+  static const char* const kDigest16x32 = "61a29bd7699e18ca6ea5641d1d023bfd";
+  static const char* const kDigest32x8 = "7f31607bd4f9ec879aa47f4daf9c7bb0";
+  static const char* const kDigest32x16 = "eb84dfab900fa6a90e132b186b4c6c36";
+  static const char* const kDigest32x32 = "e0ff35d407cb214578d61ef419c94237";
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigest4x4;
+    case kTransformSize4x8:
+      return kDigest4x8;
+    case kTransformSize4x16:
+      return kDigest4x16;
+    case kTransformSize8x4:
+      return kDigest8x4;
+    case kTransformSize8x8:
+      return kDigest8x8;
+    case kTransformSize8x16:
+      return kDigest8x16;
+    case kTransformSize8x32:
+      return kDigest8x32;
+    case kTransformSize16x4:
+      return kDigest16x4;
+    case kTransformSize16x8:
+      return kDigest16x8;
+    case kTransformSize16x16:
+      return kDigest16x16;
+    case kTransformSize16x32:
+      return kDigest16x32;
+    case kTransformSize32x8:
+      return kDigest32x8;
+    case kTransformSize32x16:
+      return kDigest32x16;
+    case kTransformSize32x32:
+      return kDigest32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflIntraPredTest8bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflIntraPredDigest8bpp(tx_size_), num_runs);
+}
+
+TEST_P(CflIntraPredTest8bpp, FixedInput) {
+  TestSpeed(GetCflIntraPredDigest8bpp(tx_size_), 1);
+}
+
+TEST_P(CflIntraPredTest8bpp, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflIntraPredTest8bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+using CflSubsamplerTest8bpp444 =
+    CflSubsamplerTest<8, uint8_t, kSubsamplingType444>;
+using CflSubsamplerTest8bpp422 =
+    CflSubsamplerTest<8, uint8_t, kSubsamplingType422>;
+using CflSubsamplerTest8bpp420 =
+    CflSubsamplerTest<8, uint8_t, kSubsamplingType420>;
+
+const char* GetCflSubsamplerDigest8bpp(TransformSize tx_size,
+                                       SubsamplingType subsampling_type) {
+  static const char* const kDigests4x4[3] = {
+      "a8fa98d76cc3ccffcffc0d02dfae052c", "929cf2c23d926b500616797f8b1baf5b",
+      "1d03f091956838e7f2b113aabd8b9da9"};
+  static const char* const kDigests4x8[3] = {
+      "717b84f867f413c87c90a7c5d0125c8c", "6ccd9f48842b1a802e128b46b8f4885d",
+      "68a334f5d2abecbc78562b3280b5fb0c"};
+  static const char* const kDigests4x16[3] = {
+      "ecd1340b7e065dd8807fd9861abb7d99", "042c3fee17df7ef8fb8cef616f212a91",
+      "b0600f0bc3fbfc374bb3628360dcae5c"};
+  static const char* const kDigests8x4[3] = {
+      "4ea5617f4ed8e9edc2fff88d0ab8e53f", "b02288905f218c9f54ce4a472ec7b22e",
+      "3522d3a4dd3839d1a86fb39b31a86d52"};
+  static const char* const kDigests8x8[3] = {
+      "a0488493e6bcdb868713a95f9b4a0091", "ff6c1ac1d94fce63c282ba49186529bf",
+      "082e34ba04d04d7cd6fe408823987602"};
+  static const char* const kDigests8x16[3] = {
+      "e01dd4bb21daaa6e991cd5b1e6f30300", "2a1b13f932e39cc5f561afea9956f47a",
+      "d8d266282cb7123f780bd7266e8f5913"};
+  static const char* const kDigests8x32[3] = {
+      "0fc95e4ab798b95ccd2966ff75028b03", "6bc6e45ef2f664134449342fe76006ff",
+      "d294fb6399edaa267aa167407c0ebccb"};
+  static const char* const kDigests16x4[3] = {
+      "4798c2cf649b786bd153ad88353d52aa", "43a4bfa3b8caf4b72f58c6a1d1054f64",
+      "a928ebbec2db1508c8831a440d82eb98"};
+  static const char* const kDigests16x8[3] = {
+      "736b7f5b603cb34abcbe1b7e69b6ce93", "90422000ab20ecb519e4d277a9b3ea2b",
+      "c8e71c2fddbb850c5a50592ee5975368"};
+  static const char* const kDigests16x16[3] = {
+      "4f15a694966ee50a9e987e9a0aa2423b", "9e31e2f5a7ce7bef738b135755e25dcd",
+      "2ffeed4d592a0455f6d888913969827f"};
+  static const char* const kDigests16x32[3] = {
+      "3a10438bfe17ea39efad20608a0520eb", "79e8e8732a6ffc29dfbb0b3fc29c2883",
+      "185ca976ccbef7fb5f3f8c6aa22d5a79"};
+  static const char* const kDigests32x8[3] = {
+      "683704f08839a15e42603e4977a3e815", "13d311635372aee8998fca1758e75e20",
+      "9847d88eaaa57c086a2e6aed583048d3"};
+  static const char* const kDigests32x16[3] = {
+      "14b6761bf9f1156cf2496f532512aa99", "ee57bb7f0aa2302d29cdc1bfce72d5fc",
+      "a4189655fe714b82eb88cb5092c0ad76"};
+  static const char* const kDigests32x32[3] = {
+      "dcfbe71b70a37418ccb90dbf27f04226", "c578556a584019c1bdc2d0c3b9fd0c88",
+      "db200bc8ccbeacd6a42d6b8e5ad1d931"};
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4[subsampling_type];
+    case kTransformSize4x8:
+      return kDigests4x8[subsampling_type];
+    case kTransformSize4x16:
+      return kDigests4x16[subsampling_type];
+    case kTransformSize8x4:
+      return kDigests8x4[subsampling_type];
+    case kTransformSize8x8:
+      return kDigests8x8[subsampling_type];
+    case kTransformSize8x16:
+      return kDigests8x16[subsampling_type];
+    case kTransformSize8x32:
+      return kDigests8x32[subsampling_type];
+    case kTransformSize16x4:
+      return kDigests16x4[subsampling_type];
+    case kTransformSize16x8:
+      return kDigests16x8[subsampling_type];
+    case kTransformSize16x16:
+      return kDigests16x16[subsampling_type];
+    case kTransformSize16x32:
+      return kDigests16x32[subsampling_type];
+    case kTransformSize32x8:
+      return kDigests32x8[subsampling_type];
+    case kTransformSize32x16:
+      return kDigests32x16[subsampling_type];
+    case kTransformSize32x32:
+      return kDigests32x32[subsampling_type];
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflSubsamplerTest8bpp444, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest8bpp444, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest8bpp444, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest8bpp444, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest8bpp422, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest8bpp422, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest8bpp422, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest8bpp422, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest8bpp420, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest8bpp420, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest8bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest8bpp420, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest8bpp420, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using CflIntraPredTest10bpp = CflIntraPredTest<10, uint16_t>;
+
+const char* GetCflIntraPredDigest10bpp(TransformSize tx_size) {
+  static const char* const kDigest4x4 = "b4ca5f6fbb643a94eb05d59976d44c5d";
+  static const char* const kDigest4x8 = "040139b76ee22af05c56baf887d3d43b";
+  static const char* const kDigest4x16 = "4a1d59ace84ff07e68a0d30e9b1cebdd";
+  static const char* const kDigest8x4 = "c2c149cea5fdcd18bfe5c19ec2a8aa90";
+  static const char* const kDigest8x8 = "68ad90bd6f409548fa5551496b7cb0d0";
+  static const char* const kDigest8x16 = "bdc54eff4de8c5d597b03afaa705d3fe";
+  static const char* const kDigest8x32 = "362aebc6d68ff0d312d55dcd6a8a927d";
+  static const char* const kDigest16x4 = "349e813aedd211581c5e64ba1938eaa7";
+  static const char* const kDigest16x8 = "35c64f6da17f836618b5804185cf3eef";
+  static const char* const kDigest16x16 = "95be0c78dbd8dda793c62c6635b4bfb7";
+  static const char* const kDigest16x32 = "4752b9eda069854d3f5c56d3f2057e79";
+  static const char* const kDigest32x8 = "dafc5e973e4b6a55861f4586a11b7dd1";
+  static const char* const kDigest32x16 = "1e177ed3914a165183916aca1d01bb74";
+  static const char* const kDigest32x32 = "4c9ab3cf9baa27bb34e29729dabc1ea6";
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigest4x4;
+    case kTransformSize4x8:
+      return kDigest4x8;
+    case kTransformSize4x16:
+      return kDigest4x16;
+    case kTransformSize8x4:
+      return kDigest8x4;
+    case kTransformSize8x8:
+      return kDigest8x8;
+    case kTransformSize8x16:
+      return kDigest8x16;
+    case kTransformSize8x32:
+      return kDigest8x32;
+    case kTransformSize16x4:
+      return kDigest16x4;
+    case kTransformSize16x8:
+      return kDigest16x8;
+    case kTransformSize16x16:
+      return kDigest16x16;
+    case kTransformSize16x32:
+      return kDigest16x32;
+    case kTransformSize32x8:
+      return kDigest32x8;
+    case kTransformSize32x16:
+      return kDigest32x16;
+    case kTransformSize32x32:
+      return kDigest32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflIntraPredTest10bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflIntraPredDigest10bpp(tx_size_), num_runs);
+}
+
+TEST_P(CflIntraPredTest10bpp, FixedInput) {
+  TestSpeed(GetCflIntraPredDigest10bpp(tx_size_), 1);
+}
+
+TEST_P(CflIntraPredTest10bpp, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflIntraPredTest10bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+using CflSubsamplerTest10bpp444 =
+    CflSubsamplerTest<10, uint16_t, kSubsamplingType444>;
+using CflSubsamplerTest10bpp422 =
+    CflSubsamplerTest<10, uint16_t, kSubsamplingType422>;
+using CflSubsamplerTest10bpp420 =
+    CflSubsamplerTest<10, uint16_t, kSubsamplingType420>;
+
+const char* GetCflSubsamplerDigest10bpp(TransformSize tx_size,
+                                        SubsamplingType subsampling_type) {
+  static const char* const kDigests4x4[3] = {
+      "a8abcad9a6c9b046a100689135a108cb", "01081c2a0d0c15dabdbc725be5660451",
+      "93d1d9df2861240d88f5618e42178654"};
+  static const char* const kDigests4x8[3] = {
+      "d1fd8cd0709ca6634ad85f3e331672e1", "0d603fcc910aca3db41fc7f64e826c27",
+      "cf88b6d1b7b025cfa0082361775aeb75"};
+  static const char* const kDigests4x16[3] = {
+      "ce2e036a950388a564d8637b1416a6c6", "6c36c46cd72057a6b36bc12188b6d22c",
+      "0884a0e53384cd5173035ad8966d8f2f"};
+  static const char* const kDigests8x4[3] = {
+      "174e961983ed71fb105ed71aa3f9daf5", "330946cc369a534618a1014b4e3f6f18",
+      "8070668aa389c1d09f8aaf43c1223e8c"};
+  static const char* const kDigests8x8[3] = {
+      "86884feb35217010f73ccdbadecb635e", "b8cbc646e1bf1352e5b4b599eaef1193",
+      "4a1110382e56b42d3b7a4132bccc01ee"};
+  static const char* const kDigests8x16[3] = {
+      "a694c4e1f89648ffb49efd6a1d35b300", "864b9da67d23a2f8284b28b2a1e5aa30",
+      "bd012ca1cea256dd02c231339a4cf200"};
+  static const char* const kDigests8x32[3] = {
+      "60c42201bc24e518c1a3b3b6306d8125", "4d530e47c2b7555d5f311ee910d61842",
+      "71888b17b832ef55c0cd9449c0e6b077"};
+  static const char* const kDigests16x4[3] = {
+      "6b6d5ae4cc294c070ce65ab31c5a7d4f", "0fbecee20d294939e7a0183c2b4a0b96",
+      "917cd884923139d5c05a11000722e3b6"};
+  static const char* const kDigests16x8[3] = {
+      "688c41726d9ac35fb5b18c57bca76b9c", "d439a2e0a60d672b644cd1189e2858b9",
+      "edded6d166a77a6c3ff46fddc13f372f"};
+  static const char* const kDigests16x16[3] = {
+      "feb2bad9f6bb3f60eaeaf6c1bfd89ca5", "d65cabce5fcd9a29d1dfc530e4764f3a",
+      "2f1a91898812d2c9320c7506b3a72eb4"};
+  static const char* const kDigests16x32[3] = {
+      "6f23b1851444d29633e62ce77bf09559", "4a449fd078bd0c9657cdc24b709c0796",
+      "e44e18cb8bda2d34b52c96d5b6b510be"};
+  static const char* const kDigests32x8[3] = {
+      "77bf9ba56f7e1d2f04068a8a00b139da", "a85a1dea82963dedab9a2f7ad4169b5f",
+      "d12746071bee96ddc075c6368bc9fbaf"};
+  static const char* const kDigests32x16[3] = {
+      "cce3422f7f8cf57145f979359ac92f98", "1c18738d40bfa91296e5fdb7230bf9a7",
+      "02513142d109aee10f081cacfb33d1c5"};
+  static const char* const kDigests32x32[3] = {
+      "789008e49d0276de186af968196dd4a7", "b8848b00968a7ba4787765b7214da05f",
+      "12d13828db57605b00ce99469489651d"};
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4[subsampling_type];
+    case kTransformSize4x8:
+      return kDigests4x8[subsampling_type];
+    case kTransformSize4x16:
+      return kDigests4x16[subsampling_type];
+    case kTransformSize8x4:
+      return kDigests8x4[subsampling_type];
+    case kTransformSize8x8:
+      return kDigests8x8[subsampling_type];
+    case kTransformSize8x16:
+      return kDigests8x16[subsampling_type];
+    case kTransformSize8x32:
+      return kDigests8x32[subsampling_type];
+    case kTransformSize16x4:
+      return kDigests16x4[subsampling_type];
+    case kTransformSize16x8:
+      return kDigests16x8[subsampling_type];
+    case kTransformSize16x16:
+      return kDigests16x16[subsampling_type];
+    case kTransformSize16x32:
+      return kDigests16x32[subsampling_type];
+    case kTransformSize32x8:
+      return kDigests32x8[subsampling_type];
+    case kTransformSize32x16:
+      return kDigests32x16[subsampling_type];
+    case kTransformSize32x32:
+      return kDigests32x32[subsampling_type];
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflSubsamplerTest10bpp444, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest10bpp444, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest10bpp444, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest10bpp444, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest10bpp422, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest10bpp422, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest10bpp422, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest10bpp422, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest10bpp420, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest10bpp420, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest10bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest10bpp420, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest10bpp420, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using CflIntraPredTest12bpp = CflIntraPredTest<12, uint16_t>;
+
+const char* GetCflIntraPredDigest12bpp(TransformSize tx_size) {
+  static const char* const kDigest4x4 = "1d92a681a58f99396f22acd8b3154e2b";
+  static const char* const kDigest4x8 = "cf6833ebc64c9ae45f192ee384ef4aa3";
+  static const char* const kDigest4x16 = "06a4fbb8590aca98a045c902ed15c777";
+  static const char* const kDigest8x4 = "ad5944c7455f731ae8dd28b2b25a1b9f";
+  static const char* const kDigest8x8 = "c19621e42ca2bc184d5065131d27be2c";
+  static const char* const kDigest8x16 = "8faa7c95e8c3c18621168ed6759c1ac1";
+  static const char* const kDigest8x32 = "502699ef7a8c7aebc8c3bc653e733703";
+  static const char* const kDigest16x4 = "7f30bb038217967336fb8548a6f7df45";
+  static const char* const kDigest16x8 = "b70943098d0fb256c2943e2ebdbe6d34";
+  static const char* const kDigest16x16 = "4c34f5669880ab78d648b16b68ea0c24";
+  static const char* const kDigest16x32 = "5d85daf690020ed235617870a1a179b1";
+  static const char* const kDigest32x8 = "f8eec12e58c469ffb698fc60b13b927c";
+  static const char* const kDigest32x16 = "f272bb7e5d2df333aa63d806c95e6748";
+  static const char* const kDigest32x32 = "c737987c0a5414b03e6014f145dd999c";
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigest4x4;
+    case kTransformSize4x8:
+      return kDigest4x8;
+    case kTransformSize4x16:
+      return kDigest4x16;
+    case kTransformSize8x4:
+      return kDigest8x4;
+    case kTransformSize8x8:
+      return kDigest8x8;
+    case kTransformSize8x16:
+      return kDigest8x16;
+    case kTransformSize8x32:
+      return kDigest8x32;
+    case kTransformSize16x4:
+      return kDigest16x4;
+    case kTransformSize16x8:
+      return kDigest16x8;
+    case kTransformSize16x16:
+      return kDigest16x16;
+    case kTransformSize16x32:
+      return kDigest16x32;
+    case kTransformSize32x8:
+      return kDigest32x8;
+    case kTransformSize32x16:
+      return kDigest32x16;
+    case kTransformSize32x32:
+      return kDigest32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflIntraPredTest12bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflIntraPredDigest12bpp(tx_size_), num_runs);
+}
+
+TEST_P(CflIntraPredTest12bpp, FixedInput) {
+  TestSpeed(GetCflIntraPredDigest12bpp(tx_size_), 1);
+}
+
+TEST_P(CflIntraPredTest12bpp, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflIntraPredTest12bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+using CflSubsamplerTest12bpp444 =
+    CflSubsamplerTest<12, uint16_t, kSubsamplingType444>;
+using CflSubsamplerTest12bpp422 =
+    CflSubsamplerTest<12, uint16_t, kSubsamplingType422>;
+using CflSubsamplerTest12bpp420 =
+    CflSubsamplerTest<12, uint16_t, kSubsamplingType420>;
+
+const char* GetCflSubsamplerDigest12bpp(TransformSize tx_size,
+                                        SubsamplingType subsampling_type) {
+  static const char* const kDigests4x4[3] = {
+      "44af37c60e9ccaacea004b57d5dea4cf",
+      "e29dd1d93f23b23778ed8cd85910d987",
+      "81e5dac2fd4c90f872ab814ed0f76ae5",
+  };
+  static const char* const kDigests4x8[3] = {
+      "bfc04aed9fe41ec07b0462a219652d16",
+      "693dd064636a0aa3be7aa098e867c512",
+      "0636c25d88aacd85d63e56011e7c5d15",
+  };
+  static const char* const kDigests4x16[3] = {
+      "6479ab30377288e75a78068d47c7e194",
+      "7d6f9b8b3eb85e73626118fc9210e622",
+      "1f3d474cd7c86899da90e515b8b7a906",
+  };
+  static const char* const kDigests8x4[3] = {
+      "7da5a2029bcdab159225c475fdff02da",
+      "096bfef24caa0670d2cd7b0bb63a7ba6",
+      "f749310dfc8a6129ed438dbc845470c0",
+  };
+  static const char* const kDigests8x8[3] = {
+      "08494051a7ff50718313a79ec7c51f92",
+      "637efad0630e253f7cce11af1a0af456",
+      "b220faf7dfedef860d59079dcf201757",
+  };
+  static const char* const kDigests8x16[3] = {
+      "19f027af516e88d3b9e613e578deb126",
+      "4f3bb155d70f9ea76d05b2f41b297a0c",
+      "b7504347eeda1e59ba8e36385c219e40",
+  };
+  static const char* const kDigests8x32[3] = {
+      "b8f1ef01c5672c87ee1004bb3cd7b8bc",
+      "b3e3318b050eb1c165d1e320ef622fa7",
+      "67754f7c5ae84dc23bb76ffaa2fa848e",
+  };
+  static const char* const kDigests16x4[3] = {
+      "f687fb4e22d8a1446eeb4915036874f4",
+      "7b5ef3d393a98dfe0ba49a0db2083465",
+      "840bbb6edaa50e9f7d391033a3dda2d9",
+  };
+  static const char* const kDigests16x8[3] = {
+      "dd9aed11d115a028035f0cee5b90d433",
+      "340d5d0784356ea199d3d751f4d6ed5e",
+      "e55f6fb5f34d829727e9dc2068098933",
+  };
+  static const char* const kDigests16x16[3] = {
+      "1df36a20d76a405c6273b88b38693cf9",
+      "2a7590d01df60b4bc6f10bfdb07b7a65",
+      "510ee31a5bd609e8f4542bb817539668",
+  };
+  static const char* const kDigests16x32[3] = {
+      "bdbc13b9fb7c3c50d25fda57f86f5ad9",
+      "7c138c568794b3d0c8aabff2edc07efd",
+      "581bef267c2a66e4c2fb079968440dbe",
+  };
+  static const char* const kDigests32x8[3] = {
+      "26f62743793811475e2afe1414c5fee1",
+      "6e6bf1678a04f2f727f0679564fb3630",
+      "a4c15562c26dbcfa43fe03a2b6e728b5",
+  };
+  static const char* const kDigests32x16[3] = {
+      "791f0713bbf032081da8ec08e58b9cd3",
+      "5dc7a673e92767186ae86996f4a30691",
+      "651f09d1244c817d92d1baa094c86f56",
+  };
+  static const char* const kDigests32x32[3] = {
+      "543a9d76e7238d88ba86218ec47c1f49",
+      "b0f2b29aae4858c1f09c27fc4344fd15",
+      "1d45083875fed14c4e5f149384a3cd2d",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4[subsampling_type];
+    case kTransformSize4x8:
+      return kDigests4x8[subsampling_type];
+    case kTransformSize4x16:
+      return kDigests4x16[subsampling_type];
+    case kTransformSize8x4:
+      return kDigests8x4[subsampling_type];
+    case kTransformSize8x8:
+      return kDigests8x8[subsampling_type];
+    case kTransformSize8x16:
+      return kDigests8x16[subsampling_type];
+    case kTransformSize8x32:
+      return kDigests8x32[subsampling_type];
+    case kTransformSize16x4:
+      return kDigests16x4[subsampling_type];
+    case kTransformSize16x8:
+      return kDigests16x8[subsampling_type];
+    case kTransformSize16x16:
+      return kDigests16x16[subsampling_type];
+    case kTransformSize16x32:
+      return kDigests16x32[subsampling_type];
+    case kTransformSize32x8:
+      return kDigests32x8[subsampling_type];
+    case kTransformSize32x16:
+      return kDigests32x16[subsampling_type];
+    case kTransformSize32x32:
+      return kDigests32x32[subsampling_type];
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(CflSubsamplerTest12bpp444, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest12bpp444, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest12bpp444, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest12bpp444, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest12bpp422, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest12bpp422, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest12bpp422, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest12bpp422, Random) { TestRandomValues(); }
+
+TEST_P(CflSubsamplerTest12bpp420, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), num_runs);
+}
+
+TEST_P(CflSubsamplerTest12bpp420, FixedInput) {
+  TestSpeed(GetCflSubsamplerDigest12bpp(tx_size_, SubsamplingType()), 1);
+}
+
+TEST_P(CflSubsamplerTest12bpp420, Overflow) { TestSaturatedValues(); }
+
+TEST_P(CflSubsamplerTest12bpp420, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+// Cfl predictors are available only for transform sizes with
+// max(width, height) <= 32.
+constexpr TransformSize kTransformSizesSmallerThan32x32[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize32x8,
+    kTransformSize32x16, kTransformSize32x32};
+
+INSTANTIATE_TEST_SUITE_P(C, CflIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest8bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest8bpp422,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest8bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, CflIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(SSE41, CflSubsamplerTest8bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(SSE41, CflSubsamplerTest8bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CflIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(NEON, CflSubsamplerTest8bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(NEON, CflSubsamplerTest8bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, CflIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest10bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest10bpp422,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest10bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, CflIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(SSE41, CflSubsamplerTest10bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(SSE41, CflSubsamplerTest10bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, CflIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(NEON, CflSubsamplerTest10bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(NEON, CflSubsamplerTest10bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, CflIntraPredTest12bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest12bpp444,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest12bpp422,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+INSTANTIATE_TEST_SUITE_P(C, CflSubsamplerTest12bpp420,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const TransformSize tx_size) {
+  return os << ToString(tx_size);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/intrapred_directional_test.cc b/src/dsp/intrapred_directional_test.cc
new file mode 100644
index 0000000..8d4fa63
--- /dev/null
+++ b/src/dsp/intrapred_directional_test.cc
@@ -0,0 +1,1126 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/intrapred_directional.h"
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockSize = 64;
+constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
+constexpr int kNumDirectionalIntraPredictors = 3;
+
+constexpr int kBaseAngles[] = {45, 67, 90, 113, 135, 157, 180, 203};
+
+const char* const kDirectionalPredNames[kNumDirectionalIntraPredictors] = {
+    "kDirectionalIntraPredictorZone1", "kDirectionalIntraPredictorZone2",
+    "kDirectionalIntraPredictorZone3"};
+
+int16_t GetDirectionalIntraPredictorDerivative(const int angle) {
+  EXPECT_GE(angle, 3);
+  EXPECT_LE(angle, 87);
+  return kDirectionalIntraPredictorDerivative[DivideBy2(angle) - 1];
+}
+
+template <int bitdepth, typename Pixel>
+class IntraPredTestBase : public testing::TestWithParam<TransformSize>,
+                          public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraPredTestBase() {
+    switch (tx_size_) {
+      case kNumTransformSizes:
+        EXPECT_NE(tx_size_, kNumTransformSizes);
+        break;
+      default:
+        block_width_ = kTransformWidth[tx_size_];
+        block_height_ = kTransformHeight[tx_size_];
+        break;
+    }
+  }
+
+  IntraPredTestBase(const IntraPredTestBase&) = delete;
+  IntraPredTestBase& operator=(const IntraPredTestBase&) = delete;
+  ~IntraPredTestBase() override = default;
+
+ protected:
+  struct IntraPredMem {
+    void Reset(libvpx_test::ACMRandom* rnd) {
+      ASSERT_NE(rnd, nullptr);
+#if LIBGAV1_MSAN
+      // Match the behavior of Tile::IntraPrediction to prevent warnings due to
+      // assembly code (safely) overreading to fill a register.
+      memset(left_mem, 0, sizeof(left_mem));
+      memset(top_mem, 0, sizeof(top_mem));
+#endif  // LIBGAV1_MSAN
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      const int mask = (1 << bitdepth) - 1;
+      for (auto& r : ref_src) r = rnd->Rand16() & mask;
+      for (int i = 0; i < kMaxBlockSize; ++i) left[i] = rnd->Rand16() & mask;
+      for (int i = -1; i < kMaxBlockSize; ++i) top[i] = rnd->Rand16() & mask;
+
+      // Some directional predictors require top-right, bottom-left.
+      for (int i = kMaxBlockSize; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = rnd->Rand16() & mask;
+        top[i] = rnd->Rand16() & mask;
+      }
+      // TODO(jzern): reorder this and regenerate the digests after switching
+      // random number generators.
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      left[-1] = rnd->Rand16() & mask;
+      left[-2] = rnd->Rand16() & mask;
+      top[-2] = rnd->Rand16() & mask;
+      memset(left_mem, 0, sizeof(left_mem[0]) * 14);
+      memset(top_mem, 0, sizeof(top_mem[0]) * 14);
+      memset(top_mem + kMaxBlockSize * 2 + 16, 0,
+             sizeof(top_mem[0]) * kTopMemPadding);
+    }
+
+    // Set ref_src, top-left, top and left to |pixel|.
+    void Set(const Pixel pixel) {
+#if LIBGAV1_MSAN
+      // Match the behavior of Tile::IntraPrediction to prevent warnings due to
+      // assembly code (safely) overreading to fill a register.
+      memset(left_mem, 0, sizeof(left_mem));
+      memset(top_mem, 0, sizeof(top_mem));
+#endif  // LIBGAV1_MSAN
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      for (auto& r : ref_src) r = pixel;
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      for (int i = -2; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = top[i] = pixel;
+      }
+    }
+
+    // DirectionalZone1_Large() overreads up to 7 pixels in |top_mem|.
+    static constexpr int kTopMemPadding = 7;
+    alignas(kMaxAlignment) Pixel dst[kTotalPixels];
+    alignas(kMaxAlignment) Pixel ref_src[kTotalPixels];
+    alignas(kMaxAlignment) Pixel left_mem[kMaxBlockSize * 2 + 16];
+    alignas(
+        kMaxAlignment) Pixel top_mem[kMaxBlockSize * 2 + 16 + kTopMemPadding];
+  };
+
+  void SetUp() override { test_utils::ResetDspTable(bitdepth); }
+
+  const TransformSize tx_size_ = GetParam();
+  int block_width_;
+  int block_height_;
+  IntraPredMem intra_pred_mem_;
+};
+
+//------------------------------------------------------------------------------
+// DirectionalIntraPredTest
+
+template <int bitdepth, typename Pixel>
+class DirectionalIntraPredTest : public IntraPredTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  DirectionalIntraPredTest() = default;
+  DirectionalIntraPredTest(const DirectionalIntraPredTest&) = delete;
+  DirectionalIntraPredTest& operator=(const DirectionalIntraPredTest&) = delete;
+  ~DirectionalIntraPredTest() override = default;
+
+ protected:
+  using IntraPredTestBase<bitdepth, Pixel>::tx_size_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_width_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_height_;
+  using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_;
+
+  enum Zone { kZone1, kZone2, kZone3, kNumZones };
+
+  enum { kAngleDeltaStart = -9, kAngleDeltaStop = 9, kAngleDeltaStep = 3 };
+
+  void SetUp() override {
+    IntraPredTestBase<bitdepth, Pixel>::SetUp();
+    IntraPredDirectionalInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_directional_intra_pred_zone1_ = dsp->directional_intra_predictor_zone1;
+    base_directional_intra_pred_zone2_ = dsp->directional_intra_predictor_zone2;
+    base_directional_intra_pred_zone3_ = dsp->directional_intra_predictor_zone3;
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_directional_intra_pred_zone1_ = nullptr;
+      base_directional_intra_pred_zone2_ = nullptr;
+      base_directional_intra_pred_zone3_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraPredDirectionalInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraPredDirectionalInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    cur_directional_intra_pred_zone1_ = dsp->directional_intra_predictor_zone1;
+    cur_directional_intra_pred_zone2_ = dsp->directional_intra_predictor_zone2;
+    cur_directional_intra_pred_zone3_ = dsp->directional_intra_predictor_zone3;
+
+    // Skip functions that haven't been specialized for this particular
+    // architecture.
+    if (cur_directional_intra_pred_zone1_ ==
+        base_directional_intra_pred_zone1_) {
+      cur_directional_intra_pred_zone1_ = nullptr;
+    }
+    if (cur_directional_intra_pred_zone2_ ==
+        base_directional_intra_pred_zone2_) {
+      cur_directional_intra_pred_zone2_ = nullptr;
+    }
+    if (cur_directional_intra_pred_zone3_ ==
+        base_directional_intra_pred_zone3_) {
+      cur_directional_intra_pred_zone3_ = nullptr;
+    }
+  }
+
+  bool IsEdgeUpsampled(int delta, const int filter_type) const {
+    delta = std::abs(delta);
+    if (delta == 0 || delta >= 40) return false;
+    const int block_wh = block_width_ + block_height_;
+    return (filter_type == 1) ? block_wh <= 8 : block_wh <= 16;
+  }
+
+  // Returns the minimum and maximum (exclusive) range of angles that the
+  // predictor should be applied to.
+  void GetZoneAngleRange(const Zone zone, int* const min_angle,
+                         int* const max_angle) const {
+    ASSERT_NE(min_angle, nullptr);
+    ASSERT_NE(max_angle, nullptr);
+    switch (zone) {
+        // The overall minimum angle comes from mode D45_PRED, yielding:
+        // min_angle = 45-(MAX_ANGLE_DELTA*ANGLE_STEP) = 36
+        // The overall maximum angle comes from mode D203_PRED, yielding:
+        // max_angle = 203+(MAX_ANGLE_DELTA*ANGLE_STEP) = 212
+        // The angles 180 and 90 are not permitted because they correspond to
+        // V_PRED and H_PRED, which are handled in distinct functions.
+      case kZone1:
+        *min_angle = 36;
+        *max_angle = 87;
+        break;
+      case kZone2:
+        *min_angle = 93;
+        *max_angle = 177;
+        break;
+      case kZone3:
+        *min_angle = 183;
+        *max_angle = 212;
+        break;
+      case kNumZones:
+        FAIL() << "Invalid zone value: " << zone;
+        break;
+    }
+  }
+
+  // These tests modify intra_pred_mem_.
+  void TestSpeed(const char* const digests[kNumDirectionalIntraPredictors],
+                 Zone zone, int num_runs);
+  void TestSaturatedValues();
+  void TestRandomValues();
+
+  DirectionalIntraPredictorZone1Func base_directional_intra_pred_zone1_;
+  DirectionalIntraPredictorZone2Func base_directional_intra_pred_zone2_;
+  DirectionalIntraPredictorZone3Func base_directional_intra_pred_zone3_;
+  DirectionalIntraPredictorZone1Func cur_directional_intra_pred_zone1_;
+  DirectionalIntraPredictorZone2Func cur_directional_intra_pred_zone2_;
+  DirectionalIntraPredictorZone3Func cur_directional_intra_pred_zone3_;
+};
+
+template <int bitdepth, typename Pixel>
+void DirectionalIntraPredTest<bitdepth, Pixel>::TestSpeed(
+    const char* const digests[kNumDirectionalIntraPredictors], const Zone zone,
+    const int num_runs) {
+  switch (zone) {
+    case kZone1:
+      if (cur_directional_intra_pred_zone1_ == nullptr) return;
+      break;
+    case kZone2:
+      if (cur_directional_intra_pred_zone2_ == nullptr) return;
+      break;
+    case kZone3:
+      if (cur_directional_intra_pred_zone3_ == nullptr) return;
+      break;
+    case kNumZones:
+      FAIL() << "Invalid zone value: " << zone;
+      break;
+  }
+  ASSERT_NE(digests, nullptr);
+  const Pixel* const left = intra_pred_mem_.left_mem + 16;
+  const Pixel* const top = intra_pred_mem_.top_mem + 16;
+
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  intra_pred_mem_.Reset(&rnd);
+
+  // Allocate separate blocks for each angle + filter + upsampled combination.
+  // Add a 1 pixel right border to test for overwrites.
+  static constexpr int kMaxZoneAngles = 27;  // zone 2
+  static constexpr int kMaxFilterTypes = 2;
+  static constexpr int kBlockBorder = 1;
+  static constexpr int kBorderSize =
+      kBlockBorder * kMaxZoneAngles * kMaxFilterTypes;
+  const int ref_stride =
+      kMaxZoneAngles * kMaxFilterTypes * block_width_ + kBorderSize;
+  const size_t ref_alloc_size = sizeof(Pixel) * ref_stride * block_height_;
+
+  using AlignedPtr = std::unique_ptr<Pixel[], decltype(&AlignedFree)>;
+  AlignedPtr ref_src(static_cast<Pixel*>(AlignedAlloc(16, ref_alloc_size)),
+                     &AlignedFree);
+  AlignedPtr dest(static_cast<Pixel*>(AlignedAlloc(16, ref_alloc_size)),
+                  &AlignedFree);
+  ASSERT_NE(ref_src, nullptr);
+  ASSERT_NE(dest, nullptr);
+
+  const int mask = (1 << bitdepth) - 1;
+  for (size_t i = 0; i < ref_alloc_size / sizeof(ref_src[0]); ++i) {
+    ref_src[i] = rnd.Rand16() & mask;
+  }
+
+  int min_angle = 0, max_angle = 0;
+  ASSERT_NO_FATAL_FAILURE(GetZoneAngleRange(zone, &min_angle, &max_angle));
+
+  absl::Duration elapsed_time;
+  for (int run = 0; run < num_runs; ++run) {
+    Pixel* dst = dest.get();
+    memcpy(dst, ref_src.get(), ref_alloc_size);
+    for (const auto& base_angle : kBaseAngles) {
+      for (int filter_type = 0; filter_type <= 1; ++filter_type) {
+        for (int angle_delta = kAngleDeltaStart; angle_delta <= kAngleDeltaStop;
+             angle_delta += kAngleDeltaStep) {
+          const int predictor_angle = base_angle + angle_delta;
+          if (predictor_angle < min_angle || predictor_angle > max_angle) {
+            continue;
+          }
+
+          ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle
+                                        << " angle_delta: " << angle_delta;
+          const bool upsampled_left =
+              IsEdgeUpsampled(predictor_angle - 180, filter_type);
+          const bool upsampled_top =
+              IsEdgeUpsampled(predictor_angle - 90, filter_type);
+          const ptrdiff_t stride = ref_stride * sizeof(ref_src[0]);
+          if (predictor_angle < 90) {
+            ASSERT_EQ(zone, kZone1);
+            const int xstep =
+                GetDirectionalIntraPredictorDerivative(predictor_angle);
+            const absl::Time start = absl::Now();
+            cur_directional_intra_pred_zone1_(dst, stride, top, block_width_,
+                                              block_height_, xstep,
+                                              upsampled_top);
+            elapsed_time += absl::Now() - start;
+          } else if (predictor_angle < 180) {
+            ASSERT_EQ(zone, kZone2);
+            const int xstep =
+                GetDirectionalIntraPredictorDerivative(180 - predictor_angle);
+            const int ystep =
+                GetDirectionalIntraPredictorDerivative(predictor_angle - 90);
+            const absl::Time start = absl::Now();
+            cur_directional_intra_pred_zone2_(
+                dst, stride, top, left, block_width_, block_height_, xstep,
+                ystep, upsampled_top, upsampled_left);
+            elapsed_time += absl::Now() - start;
+          } else {
+            ASSERT_EQ(zone, kZone3);
+            ASSERT_LT(predictor_angle, 270);
+            const int ystep =
+                GetDirectionalIntraPredictorDerivative(270 - predictor_angle);
+            const absl::Time start = absl::Now();
+            cur_directional_intra_pred_zone3_(dst, stride, left, block_width_,
+                                              block_height_, ystep,
+                                              upsampled_left);
+            elapsed_time += absl::Now() - start;
+          }
+          dst += block_width_ + kBlockBorder;
+        }
+      }
+    }
+  }
+
+  test_utils::CheckMd5Digest(ToString(tx_size_), kDirectionalPredNames[zone],
+                             digests[zone], dest.get(), ref_alloc_size,
+                             elapsed_time);
+}
+
+template <int bitdepth, typename Pixel>
+void DirectionalIntraPredTest<bitdepth, Pixel>::TestSaturatedValues() {
+  const Pixel* const left = intra_pred_mem_.left_mem + 16;
+  const Pixel* const top = intra_pred_mem_.top_mem + 16;
+  const auto kMaxPixel = static_cast<Pixel>((1 << bitdepth) - 1);
+  intra_pred_mem_.Set(kMaxPixel);
+
+  for (int i = kZone1; i < kNumZones; ++i) {
+    switch (i) {
+      case kZone1:
+        if (cur_directional_intra_pred_zone1_ == nullptr) continue;
+        break;
+      case kZone2:
+        if (cur_directional_intra_pred_zone2_ == nullptr) continue;
+        break;
+      case kZone3:
+        if (cur_directional_intra_pred_zone3_ == nullptr) continue;
+        break;
+      case kNumZones:
+        FAIL() << "Invalid zone value: " << i;
+        break;
+    }
+    int min_angle = 0, max_angle = 0;
+    ASSERT_NO_FATAL_FAILURE(
+        GetZoneAngleRange(static_cast<Zone>(i), &min_angle, &max_angle));
+
+    for (const auto& base_angle : kBaseAngles) {
+      for (int filter_type = 0; filter_type <= 1; ++filter_type) {
+        for (int angle_delta = kAngleDeltaStart; angle_delta <= kAngleDeltaStop;
+             angle_delta += kAngleDeltaStep) {
+          const int predictor_angle = base_angle + angle_delta;
+          if (predictor_angle <= min_angle || predictor_angle >= max_angle) {
+            continue;
+          }
+          ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle
+                                        << " angle_delta: " << angle_delta;
+
+          memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                 sizeof(intra_pred_mem_.dst));
+
+          const bool upsampled_left =
+              IsEdgeUpsampled(predictor_angle - 180, filter_type);
+          const bool upsampled_top =
+              IsEdgeUpsampled(predictor_angle - 90, filter_type);
+          const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+          if (predictor_angle < 90) {
+            const int xstep =
+                GetDirectionalIntraPredictorDerivative(predictor_angle);
+            cur_directional_intra_pred_zone1_(intra_pred_mem_.dst, stride, top,
+                                              block_width_, block_height_,
+                                              xstep, upsampled_top);
+          } else if (predictor_angle < 180) {
+            const int xstep =
+                GetDirectionalIntraPredictorDerivative(180 - predictor_angle);
+            const int ystep =
+                GetDirectionalIntraPredictorDerivative(predictor_angle - 90);
+            cur_directional_intra_pred_zone2_(
+                intra_pred_mem_.dst, stride, top, left, block_width_,
+                block_height_, xstep, ystep, upsampled_top, upsampled_left);
+          } else {
+            ASSERT_LT(predictor_angle, 270);
+            const int ystep =
+                GetDirectionalIntraPredictorDerivative(270 - predictor_angle);
+            cur_directional_intra_pred_zone3_(intra_pred_mem_.dst, stride, left,
+                                              block_width_, block_height_,
+                                              ystep, upsampled_left);
+          }
+
+          if (!test_utils::CompareBlocks(
+                  intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_,
+                  block_height_, kMaxBlockSize, kMaxBlockSize, true)) {
+            ADD_FAILURE() << "Expected " << kDirectionalPredNames[i]
+                          << " (angle: " << predictor_angle
+                          << " filter type: " << filter_type
+                          << ") to produce a block containing '"
+                          << static_cast<int>(kMaxPixel) << "'";
+            return;
+          }
+        }
+      }
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void DirectionalIntraPredTest<bitdepth, Pixel>::TestRandomValues() {
+  const Pixel* const left = intra_pred_mem_.left_mem + 16;
+  const Pixel* const top = intra_pred_mem_.top_mem + 16;
+  // Use an alternate seed to differentiate this test from TestSpeed().
+  libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed);
+
+  for (int i = kZone1; i < kNumZones; ++i) {
+    // Only run when there is a reference version (base) and a different
+    // optimized version (cur).
+    switch (i) {
+      case kZone1:
+        if (base_directional_intra_pred_zone1_ == nullptr ||
+            cur_directional_intra_pred_zone1_ == nullptr) {
+          continue;
+        }
+        break;
+      case kZone2:
+        if (base_directional_intra_pred_zone2_ == nullptr ||
+            cur_directional_intra_pred_zone2_ == nullptr) {
+          continue;
+        }
+        break;
+      case kZone3:
+        if (base_directional_intra_pred_zone3_ == nullptr ||
+            cur_directional_intra_pred_zone3_ == nullptr) {
+          continue;
+        }
+        break;
+      case kNumZones:
+        FAIL() << "Invalid zone value: " << i;
+        break;
+    }
+    int min_angle = 0, max_angle = 0;
+    ASSERT_NO_FATAL_FAILURE(
+        GetZoneAngleRange(static_cast<Zone>(i), &min_angle, &max_angle));
+
+    for (const auto& base_angle : kBaseAngles) {
+      for (int n = 0; n < 1000; ++n) {
+        for (int filter_type = 0; filter_type <= 1; ++filter_type) {
+          for (int angle_delta = kAngleDeltaStart;
+               angle_delta <= kAngleDeltaStop; angle_delta += kAngleDeltaStep) {
+            const int predictor_angle = base_angle + angle_delta;
+            if (predictor_angle <= min_angle || predictor_angle >= max_angle) {
+              continue;
+            }
+            ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle
+                                          << " angle_delta: " << angle_delta;
+
+            intra_pred_mem_.Reset(&rnd);
+            memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                   sizeof(intra_pred_mem_.dst));
+
+            const bool upsampled_left =
+                IsEdgeUpsampled(predictor_angle - 180, filter_type);
+            const bool upsampled_top =
+                IsEdgeUpsampled(predictor_angle - 90, filter_type);
+            const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+            if (predictor_angle < 90) {
+              const int xstep =
+                  GetDirectionalIntraPredictorDerivative(predictor_angle);
+              base_directional_intra_pred_zone1_(
+                  intra_pred_mem_.ref_src, stride, top, block_width_,
+                  block_height_, xstep, upsampled_top);
+              cur_directional_intra_pred_zone1_(
+                  intra_pred_mem_.dst, stride, top, block_width_, block_height_,
+                  xstep, upsampled_top);
+            } else if (predictor_angle < 180) {
+              const int xstep =
+                  GetDirectionalIntraPredictorDerivative(180 - predictor_angle);
+              const int ystep =
+                  GetDirectionalIntraPredictorDerivative(predictor_angle - 90);
+              base_directional_intra_pred_zone2_(
+                  intra_pred_mem_.ref_src, stride, top, left, block_width_,
+                  block_height_, xstep, ystep, upsampled_top, upsampled_left);
+              cur_directional_intra_pred_zone2_(
+                  intra_pred_mem_.dst, stride, top, left, block_width_,
+                  block_height_, xstep, ystep, upsampled_top, upsampled_left);
+            } else {
+              ASSERT_LT(predictor_angle, 270);
+              const int ystep =
+                  GetDirectionalIntraPredictorDerivative(270 - predictor_angle);
+              base_directional_intra_pred_zone3_(
+                  intra_pred_mem_.ref_src, stride, left, block_width_,
+                  block_height_, ystep, upsampled_left);
+              cur_directional_intra_pred_zone3_(
+                  intra_pred_mem_.dst, stride, left, block_width_,
+                  block_height_, ystep, upsampled_left);
+            }
+
+            if (!test_utils::CompareBlocks(
+                    intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_,
+                    block_height_, kMaxBlockSize, kMaxBlockSize, true)) {
+              ADD_FAILURE() << "Result from optimized version of "
+                            << kDirectionalPredNames[i]
+                            << " differs from reference at angle "
+                            << predictor_angle << " with filter type "
+                            << filter_type << " in iteration #" << n;
+              return;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+using DirectionalIntraPredTest8bpp = DirectionalIntraPredTest<8, uint8_t>;
+
+const char* const* GetDirectionalIntraPredDigests8bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumDirectionalIntraPredictors] = {
+      "9cfc1da729ad08682e165826c29b280b",
+      "bb73539c7afbda7bddd2184723b932d6",
+      "9d2882800ffe948196e984a26a2da72c",
+  };
+  static const char* const kDigests4x8[kNumDirectionalIntraPredictors] = {
+      "090efe6f83cc6fa301f65d3bbd5c38d2",
+      "d0fba4cdfb90f8bd293a94cae9db1a15",
+      "f7ad0eeab4389d0baa485d30fec87617",
+  };
+  static const char* const kDigests4x16[kNumDirectionalIntraPredictors] = {
+      "1d32b33c75fe85248c48cdc8caa78d84",
+      "7000e18159443d366129a6cc6ef8fcee",
+      "06c02fac5f8575f687abb3f634eb0b4c",
+  };
+  static const char* const kDigests8x4[kNumDirectionalIntraPredictors] = {
+      "1b591799685bc135982114b731293f78",
+      "5cd9099acb9f7b2618dafa6712666580",
+      "d023883efede88f99c19d006044d9fa1",
+  };
+  static const char* const kDigests8x8[kNumDirectionalIntraPredictors] = {
+      "f1e46ecf62a2516852f30c5025adb7ea",
+      "864442a209c16998065af28d8cdd839a",
+      "411a6e554868982af577de69e53f12e8",
+  };
+  static const char* const kDigests8x16[kNumDirectionalIntraPredictors] = {
+      "89278302be913a85cfb06feaea339459",
+      "6c42f1a9493490cd4529fd40729cec3c",
+      "2516b5e1c681e5dcb1acedd5f3d41106",
+  };
+  static const char* const kDigests8x32[kNumDirectionalIntraPredictors] = {
+      "aea7078f3eeaa8afbfe6c959c9e676f1",
+      "cad30babf12729dda5010362223ba65c",
+      "ff384ebdc832007775af418a2aae1463",
+  };
+  static const char* const kDigests16x4[kNumDirectionalIntraPredictors] = {
+      "964a821c313c831e12f4d32e616c0b55",
+      "adf6dad3a84ab4d16c16eea218bec57a",
+      "a54fa008d43895e523474686c48a81c2",
+  };
+  static const char* const kDigests16x8[kNumDirectionalIntraPredictors] = {
+      "fe2851b4e4f9fcf924cf17d50415a4c0",
+      "50a0e279c481437ff315d08eb904c733",
+      "0682065c8fb6cbf9be4949316c87c9e5",
+  };
+  static const char* const kDigests16x16[kNumDirectionalIntraPredictors] = {
+      "ef15503b1943642e7a0bace1616c0e11",
+      "bf1a4d3f855f1072a902a88ec6ce0350",
+      "7e87a03e29cd7fd843fd71b729a18f3f",
+  };
+  static const char* const kDigests16x32[kNumDirectionalIntraPredictors] = {
+      "f7b636615d2e5bf289b5db452a6f188d",
+      "e95858c532c10d00b0ce7a02a02121dd",
+      "34a18ccf58ef490f32268e85ce8c7de4",
+  };
+  static const char* const kDigests16x64[kNumDirectionalIntraPredictors] = {
+      "b250099986c2fab9670748598058846b",
+      "f25d80af4da862a9b6b72979f1e17cb4",
+      "5347dc7bc346733b4887f6c8ad5e0898",
+  };
+  static const char* const kDigests32x8[kNumDirectionalIntraPredictors] = {
+      "72e4c9f8af043b1cb1263490351818ab",
+      "1fc010d2df011b9e4e3d0957107c78df",
+      "f4cbfa3ca941ef08b972a68d7e7bafc4",
+  };
+  static const char* const kDigests32x16[kNumDirectionalIntraPredictors] = {
+      "37e5a1aaf7549d2bce08eece9d20f0f6",
+      "6a2794025d0aca414ab17baa3cf8251a",
+      "63dd37a6efdc91eeefef166c99ce2db1",
+  };
+  static const char* const kDigests32x32[kNumDirectionalIntraPredictors] = {
+      "198aabc958992eb49cceab97d1acb43e",
+      "aee88b6c8bacfcf38799fe338e6c66e7",
+      "01e8f8f96696636f6d79d33951907a16",
+  };
+  static const char* const kDigests32x64[kNumDirectionalIntraPredictors] = {
+      "0611390202c4f90f7add7aec763ded58",
+      "960240c7ceda2ccfac7c90b71460578a",
+      "7e7d97594aab8ad56e8c01c340335607",
+  };
+  static const char* const kDigests64x16[kNumDirectionalIntraPredictors] = {
+      "7e1f567e7fc510757f2d89d638bc826f",
+      "c929d687352ce40a58670be2ce3c8c90",
+      "f6881e6a9ba3c3d3d730b425732656b1",
+  };
+  static const char* const kDigests64x32[kNumDirectionalIntraPredictors] = {
+      "27b4c2a7081d4139f22003ba8b6dfdf2",
+      "301e82740866b9274108a04c872fa848",
+      "98d3aa4fef838f4abf00dac33806659f",
+  };
+  static const char* const kDigests64x64[kNumDirectionalIntraPredictors] = {
+      "b31816db8fade3accfd975b21aa264c7",
+      "2adce01a03b9452633d5830e1a9b4e23",
+      "7b988fadba8b07c36e88d7be6b270494",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(DirectionalIntraPredTest8bpp, DISABLED_Speed) {
+#if LIBGAV1_ENABLE_NEON
+  const auto num_runs = static_cast<int>(2e5 / (block_width_ * block_height_));
+#else
+  const int num_runs = static_cast<int>(4e7 / (block_width_ * block_height_));
+#endif
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests8bpp(tx_size_),
+              static_cast<Zone>(i), num_runs);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest8bpp, FixedInput) {
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests8bpp(tx_size_),
+              static_cast<Zone>(i), 1);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest8bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(DirectionalIntraPredTest8bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using DirectionalIntraPredTest10bpp = DirectionalIntraPredTest<10, uint16_t>;
+
+const char* const* GetDirectionalIntraPredDigests10bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumDirectionalIntraPredictors] = {
+      "a683f4d7ccd978737615f61ecb4d638d",
+      "90c94374eaf7e9501f197863937b8639",
+      "0d3969cd081523ac6a906eecc7980c43",
+  };
+  static const char* const kDigests4x8[kNumDirectionalIntraPredictors] = {
+      "c3ffa2979b325644e4a56c882fe27347",
+      "1f61f5ee413a9a3b8d1d93869ec2aee0",
+      "4795ea944779ec4a783408769394d874",
+  };
+  static const char* const kDigests4x16[kNumDirectionalIntraPredictors] = {
+      "45c3282c9aa51024c1d64a40f230aa45",
+      "5cd47dd69f8bd0b15365a0c5cfc0a49a",
+      "06336c507b05f98c1d6a21abc43e6182",
+  };
+  static const char* const kDigests8x4[kNumDirectionalIntraPredictors] = {
+      "7370476ff0abbdc5e92f811b8879c861",
+      "a239a50adb28a4791b52a0dfff3bee06",
+      "4779a17f958a9ca04e8ec08c5aba1d36",
+  };
+  static const char* const kDigests8x8[kNumDirectionalIntraPredictors] = {
+      "305463f346c376594f82aad8304e0362",
+      "0cd481e5bda286c87a645417569fd948",
+      "48c7899dc9b7163b0b1f61b3a2b4b73e",
+  };
+  static const char* const kDigests8x16[kNumDirectionalIntraPredictors] = {
+      "5c18fd5339be90628c82b1fb6af50d5e",
+      "35eaa566ebd3bb7c903cfead5dc9ac78",
+      "9fdb0e790e5965810d02c02713c84071",
+  };
+  static const char* const kDigests8x32[kNumDirectionalIntraPredictors] = {
+      "2168d6cc858c704748b7b343ced2ac3a",
+      "1d3ce273107447faafd2e55877e48ffb",
+      "d344164049d1fe9b65a3ae8764bbbd37",
+  };
+  static const char* const kDigests16x4[kNumDirectionalIntraPredictors] = {
+      "dcef2cf51abe3fe150f388a14c762d30",
+      "6a810b289b1c14f8eab8ca1274e91ecd",
+      "c94da7c11f3fb11963d85c8804fce2d9",
+  };
+  static const char* const kDigests16x8[kNumDirectionalIntraPredictors] = {
+      "50a0d08b0d99b7a574bad2cfb36efc39",
+      "2dcb55874db39da70c8ca1318559f9fe",
+      "6390bcd30ff3bc389ecc0a0952bea531",
+  };
+  static const char* const kDigests16x16[kNumDirectionalIntraPredictors] = {
+      "7146c83c2620935606d49f3cb5876f41",
+      "2318ddf30c070a53c9b9cf199cd1b2c5",
+      "e9042e2124925aa7c1b6110617cb10e8",
+  };
+  static const char* const kDigests16x32[kNumDirectionalIntraPredictors] = {
+      "c970f401de7b7c5bb4e3ad447fcbef8f",
+      "a18cc70730eecdaa31dbcf4306ff490f",
+      "32c1528ad4a576a2210399d6b4ccd46e",
+  };
+  static const char* const kDigests16x64[kNumDirectionalIntraPredictors] = {
+      "00b3f0007da2e5d01380594a3d7162d5",
+      "1971af519e4a18967b7311f93efdd1b8",
+      "e6139769ce5a9c4982cfab9363004516",
+  };
+  static const char* const kDigests32x8[kNumDirectionalIntraPredictors] = {
+      "08107ad971179cc9f465ae5966bd4901",
+      "b215212a3c0dfe9182c4f2e903d731f7",
+      "791274416a0da87c674e1ae318b3ce09",
+  };
+  static const char* const kDigests32x16[kNumDirectionalIntraPredictors] = {
+      "94ea6cccae35b5d08799aa003ac08ccf",
+      "ae105e20e63fb55d4fd9d9e59dc62dde",
+      "973d0b2358ea585e4f486e7e645c5310",
+  };
+  static const char* const kDigests32x32[kNumDirectionalIntraPredictors] = {
+      "d14c695c4853ddf5e5d8256bc1d1ed60",
+      "6bd0ebeb53adecc11442b1218b870cb7",
+      "e03bc402a9999aba8272275dce93e89f",
+  };
+  static const char* const kDigests32x64[kNumDirectionalIntraPredictors] = {
+      "b21a8a8723758392ee659eeeae518a1e",
+      "e50285454896210ce44d6f04dfde05a7",
+      "f0f8ea0c6c2acc8d7d390927c3a90370",
+  };
+  static const char* const kDigests64x16[kNumDirectionalIntraPredictors] = {
+      "ce51db16fd4fa56e601631397b098c89",
+      "aa87a8635e02c1e91d13158c61e443f6",
+      "4c1ee3afd46ef34bd711a34d0bf86f13",
+  };
+  static const char* const kDigests64x32[kNumDirectionalIntraPredictors] = {
+      "25aaf5971e24e543e3e69a47254af777",
+      "eb6f444b3df127d69460778ab5bf8fc1",
+      "2f846cc0d506f90c0a58438600819817",
+  };
+  static const char* const kDigests64x64[kNumDirectionalIntraPredictors] = {
+      "b26ce5b5f4b5d4a438b52e5987877fb8",
+      "35721a00a70938111939cf69988d928e",
+      "0af7ec35939483fac82c246a13845806",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(DirectionalIntraPredTest10bpp, DISABLED_Speed) {
+#if LIBGAV1_ENABLE_NEON
+  const int num_runs = static_cast<int>(2e5 / (block_width_ * block_height_));
+#else
+  const int num_runs = static_cast<int>(4e7 / (block_width_ * block_height_));
+#endif
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests10bpp(tx_size_),
+              static_cast<Zone>(i), num_runs);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest10bpp, FixedInput) {
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests10bpp(tx_size_),
+              static_cast<Zone>(i), 1);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest10bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(DirectionalIntraPredTest10bpp, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using DirectionalIntraPredTest12bpp = DirectionalIntraPredTest<12, uint16_t>;
+
+const char* const* GetDirectionalIntraPredDigests12bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumDirectionalIntraPredictors] = {
+      "78f3297743f75e928e755b6ffa2d3050",
+      "7315da39861c6e3ef2e47c913e3be349",
+      "5609cb40b575f24d05880df202a60bd3",
+  };
+  static const char* const kDigests4x8[kNumDirectionalIntraPredictors] = {
+      "efb2363d3c25427abe198806c8ba4d6b",
+      "b5aaa41665a10e7e7944fb7fc90fd59a",
+      "5a85610342339ca3109d775fa18dc25c",
+  };
+  static const char* const kDigests4x16[kNumDirectionalIntraPredictors] = {
+      "9045679914980ea1f579d84509397b6e",
+      "f9f50bdc9f81a93095fd9d6998174aa7",
+      "46c1f82e85b8ba5b03bab41a2f561483",
+  };
+  static const char* const kDigests8x4[kNumDirectionalIntraPredictors] = {
+      "a0ae0956b2b667c528b7803d733d49da",
+      "5d9f60ef8904c4faedb6cfc19e54418a",
+      "4ffdcbbbcb23bca8286f1c286b9cb3e8",
+  };
+  static const char* const kDigests8x8[kNumDirectionalIntraPredictors] = {
+      "086116c6b116613b8b47a086726566ea",
+      "141dca7fcae0e4d4b88887a618271ea1",
+      "3575a34278aa0fb1eed934290982f4a7",
+  };
+  static const char* const kDigests8x16[kNumDirectionalIntraPredictors] = {
+      "7922f40216c78a40abaf675667e79493",
+      "55d20588240171df2e24d105ee1563ad",
+      "674b4d8f4dbf514d22e21cc4baeda1d3",
+  };
+  static const char* const kDigests8x32[kNumDirectionalIntraPredictors] = {
+      "32d4d7e256d3b304026ddb5430cf6a09",
+      "72f4be2569f4e067c252d51ff4030de3",
+      "6779a132e1bac0ac43c2373f56553ed8",
+  };
+  static const char* const kDigests16x4[kNumDirectionalIntraPredictors] = {
+      "1be2e0efc1403f9e22cfb8aeb28763d9",
+      "558c8a5418ac91d21a5839c454a9391f",
+      "7693ebef9b86416ebd6e78e98fcafba7",
+  };
+  static const char* const kDigests16x8[kNumDirectionalIntraPredictors] = {
+      "e6217ed1c673ae42e84f8757316b580d",
+      "028aa582c11a9733f0cd693211a067c5",
+      "082de9fc7c4bc80a8ec8522b5a5cb52c",
+  };
+  static const char* const kDigests16x16[kNumDirectionalIntraPredictors] = {
+      "e3b293c09bdc9c5c543ad046a3f0d64f",
+      "2de5803a6ed497c1039c8e6d675c1dd3",
+      "05742f807560f5d5206e54b70097dc4a",
+  };
+  static const char* const kDigests16x32[kNumDirectionalIntraPredictors] = {
+      "57f2ca4ba56be253eff7e6b73df5003d",
+      "ef8bea00437e01fb798a22cda59f0191",
+      "989ff38c96600c2f108d6e6fa381fd13",
+  };
+  static const char* const kDigests16x64[kNumDirectionalIntraPredictors] = {
+      "f5540f4874c02aa2222a3ba75106f841",
+      "17e5d20f798a96c39abc8a81e7aa7bc6",
+      "0fe9ea14c9dcae466b4a36f1c7db6978",
+  };
+  static const char* const kDigests32x8[kNumDirectionalIntraPredictors] = {
+      "aff9429951ab1885c0d9ed29aa1b6a9f",
+      "4b686e2a879bf0b4aadd06b412e0eb48",
+      "39325d71cddc272bfa1dd2dc80d09ffe",
+  };
+  static const char* const kDigests32x16[kNumDirectionalIntraPredictors] = {
+      "b83dffdf8bad2b7c3808925b6138ca1e",
+      "3656b58c7aaf2025979b4a3ed8a2841e",
+      "cfcc0c6ae3fa5e7d45dec581479459f6",
+  };
+  static const char* const kDigests32x32[kNumDirectionalIntraPredictors] = {
+      "3c91b3b9e2df73ffb718e0bf53c5a5c2",
+      "0dbe27603e111158e70d99e181befb83",
+      "edecbffb32ae1e49b66b6e55ad0af6c6",
+  };
+  static const char* const kDigests32x64[kNumDirectionalIntraPredictors] = {
+      "a3290917f755c7ccdc7b77eb3c6c89a7",
+      "42f89db41fbb366ddb78ef79a043f3e3",
+      "7f7bcbe33aa003b166677c68d12490e9",
+  };
+  static const char* const kDigests64x16[kNumDirectionalIntraPredictors] = {
+      "d4f4c6b70a82695f843e9227bd7d9cc8",
+      "550a0bd87936801651d552e229b683e9",
+      "a4c730ad71f566a930c5672e1b2f48f1",
+  };
+  static const char* const kDigests64x32[kNumDirectionalIntraPredictors] = {
+      "2087c9264c4c5fea9a6fe20dcedbe2b9",
+      "d4dd51d9578a3fc2eb75086fba867c22",
+      "6121a67d63e40107e780d0938aeb3d21",
+  };
+  static const char* const kDigests64x64[kNumDirectionalIntraPredictors] = {
+      "09c3818a07bc54467634c2bfce66f58f",
+      "8da453b8d72d73d71ba15a14ddd59db4",
+      "9bc939aa54445722469b120b8a505cb3",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(DirectionalIntraPredTest12bpp, DISABLED_Speed) {
+#if LIBGAV1_ENABLE_NEON
+  const int num_runs = static_cast<int>(2e7 / (block_width_ * block_height_));
+#else
+  const int num_runs = static_cast<int>(4e7 / (block_width_ * block_height_));
+#endif
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests12bpp(tx_size_),
+              static_cast<Zone>(i), num_runs);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest12bpp, FixedInput) {
+  for (int i = kZone1; i < kNumZones; ++i) {
+    TestSpeed(GetDirectionalIntraPredDigests12bpp(tx_size_),
+              static_cast<Zone>(i), 1);
+  }
+}
+
+TEST_P(DirectionalIntraPredTest12bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(DirectionalIntraPredTest12bpp, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+constexpr TransformSize kTransformSizes[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
+    kTransformSize32x8,  kTransformSize32x16, kTransformSize32x32,
+    kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
+    kTransformSize64x64};
+
+INSTANTIATE_TEST_SUITE_P(C, DirectionalIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, DirectionalIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, DirectionalIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, DirectionalIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, DirectionalIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, DirectionalIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_NEON
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, DirectionalIntraPredTest12bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const TransformSize tx_size) {
+  return os << ToString(tx_size);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/intrapred_filter_test.cc b/src/dsp/intrapred_filter_test.cc
new file mode 100644
index 0000000..c8d60a0
--- /dev/null
+++ b/src/dsp/intrapred_filter_test.cc
@@ -0,0 +1,692 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/intrapred_filter.h"
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockSize = 64;
+constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
+
+const char* const kFilterIntraPredNames[kNumFilterIntraPredictors] = {
+    "kFilterIntraPredictorDc",         "kFilterIntraPredictorVertical",
+    "kFilterIntraPredictorHorizontal", "kFilterIntraPredictorD157",
+    "kFilterIntraPredictorPaeth",
+};
+
+template <int bitdepth, typename Pixel>
+class IntraPredTestBase : public testing::TestWithParam<TransformSize>,
+                          public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraPredTestBase() {
+    switch (tx_size_) {
+      case kNumTransformSizes:
+        EXPECT_NE(tx_size_, kNumTransformSizes);
+        break;
+      default:
+        block_width_ = kTransformWidth[tx_size_];
+        block_height_ = kTransformHeight[tx_size_];
+        break;
+    }
+  }
+
+  IntraPredTestBase(const IntraPredTestBase&) = delete;
+  IntraPredTestBase& operator=(const IntraPredTestBase&) = delete;
+  ~IntraPredTestBase() override = default;
+
+ protected:
+  struct IntraPredMem {
+    void Reset(libvpx_test::ACMRandom* rnd) {
+      ASSERT_NE(rnd, nullptr);
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      const int mask = (1 << bitdepth) - 1;
+      for (auto& r : ref_src) r = rnd->Rand16() & mask;
+      for (int i = 0; i < kMaxBlockSize; ++i) left[i] = rnd->Rand16() & mask;
+      for (int i = -1; i < kMaxBlockSize; ++i) top[i] = rnd->Rand16() & mask;
+
+      // Some directional predictors require top-right, bottom-left.
+      for (int i = kMaxBlockSize; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = rnd->Rand16() & mask;
+        top[i] = rnd->Rand16() & mask;
+      }
+      // TODO(jzern): reorder this and regenerate the digests after switching
+      // random number generators.
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      left[-1] = rnd->Rand16() & mask;
+      left[-2] = rnd->Rand16() & mask;
+      top[-2] = rnd->Rand16() & mask;
+      memset(left_mem, 0, sizeof(left_mem[0]) * 14);
+      memset(top_mem, 0, sizeof(top_mem[0]) * 14);
+      memset(top_mem + kMaxBlockSize * 2 + 16, 0,
+             sizeof(top_mem[0]) * kTopMemPadding);
+    }
+
+    // Set ref_src, top-left, top and left to |pixel|.
+    void Set(const Pixel pixel) {
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      for (auto& r : ref_src) r = pixel;
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      for (int i = -2; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = top[i] = pixel;
+      }
+    }
+
+    // DirectionalZone1_Large() overreads up to 7 pixels in |top_mem|.
+    static constexpr int kTopMemPadding = 7;
+    alignas(kMaxAlignment) Pixel dst[kTotalPixels];
+    alignas(kMaxAlignment) Pixel ref_src[kTotalPixels];
+    alignas(kMaxAlignment) Pixel left_mem[kMaxBlockSize * 2 + 16];
+    alignas(
+        kMaxAlignment) Pixel top_mem[kMaxBlockSize * 2 + 16 + kTopMemPadding];
+  };
+
+  void SetUp() override { test_utils::ResetDspTable(bitdepth); }
+
+  const TransformSize tx_size_ = GetParam();
+  int block_width_;
+  int block_height_;
+  IntraPredMem intra_pred_mem_;
+};
+
+//------------------------------------------------------------------------------
+// FilterIntraPredTest
+
+template <int bitdepth, typename Pixel>
+class FilterIntraPredTest : public IntraPredTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  FilterIntraPredTest() = default;
+  FilterIntraPredTest(const FilterIntraPredTest&) = delete;
+  FilterIntraPredTest& operator=(const FilterIntraPredTest&) = delete;
+  ~FilterIntraPredTest() override = default;
+
+ protected:
+  using IntraPredTestBase<bitdepth, Pixel>::tx_size_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_width_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_height_;
+  using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_;
+
+  void SetUp() override {
+    IntraPredTestBase<bitdepth, Pixel>::SetUp();
+    IntraPredFilterInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_filter_intra_pred_ = dsp->filter_intra_predictor;
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      // No need to compare C with itself.
+      base_filter_intra_pred_ = nullptr;
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraPredFilterInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraPredFilterInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    // Put the current architecture-specific implementation up for testing and
+    // comparison against C version.
+    cur_filter_intra_pred_ = dsp->filter_intra_predictor;
+  }
+
+  // These tests modify intra_pred_mem_.
+  void TestSpeed(const char* const digests[kNumFilterIntraPredictors],
+                 int num_runs);
+  void TestSaturatedValues();
+  void TestRandomValues();
+
+  FilterIntraPredictorFunc base_filter_intra_pred_;
+  FilterIntraPredictorFunc cur_filter_intra_pred_;
+};
+
+template <int bitdepth, typename Pixel>
+void FilterIntraPredTest<bitdepth, Pixel>::TestSpeed(
+    const char* const digests[kNumFilterIntraPredictors], const int num_runs) {
+  ASSERT_NE(digests, nullptr);
+  const Pixel* const left = intra_pred_mem_.left_mem + 16;
+  const Pixel* const top = intra_pred_mem_.top_mem + 16;
+
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  intra_pred_mem_.Reset(&rnd);
+
+  // IntraPredInit_C() leaves the filter function empty.
+  if (cur_filter_intra_pred_ == nullptr) return;
+  for (int i = 0; i < kNumFilterIntraPredictors; ++i) {
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const absl::Time start = absl::Now();
+    for (int run = 0; run < num_runs; ++run) {
+      const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+      cur_filter_intra_pred_(intra_pred_mem_.dst, stride, top, left,
+                             static_cast<FilterIntraPredictor>(i), block_width_,
+                             block_height_);
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    test_utils::CheckMd5Digest(ToString(tx_size_), kFilterIntraPredNames[i],
+                               digests[i], intra_pred_mem_.dst,
+                               sizeof(intra_pred_mem_.dst), elapsed_time);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void FilterIntraPredTest<bitdepth, Pixel>::TestSaturatedValues() {
+  Pixel* const left = intra_pred_mem_.left_mem + 16;
+  Pixel* const top = intra_pred_mem_.top_mem + 16;
+  const auto kMaxPixel = static_cast<Pixel>((1 << bitdepth) - 1);
+  intra_pred_mem_.Set(kMaxPixel);
+
+  // IntraPredInit_C() leaves the filter function empty.
+  if (cur_filter_intra_pred_ == nullptr) return;
+  for (int i = 0; i < kNumFilterIntraPredictors; ++i) {
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+    cur_filter_intra_pred_(intra_pred_mem_.dst, stride, top, left,
+                           static_cast<FilterIntraPredictor>(i), block_width_,
+                           block_height_);
+    if (!test_utils::CompareBlocks(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                                   block_width_, block_height_, kMaxBlockSize,
+                                   kMaxBlockSize, true)) {
+      ADD_FAILURE() << "Expected " << kFilterIntraPredNames[i]
+                    << " to produce a block containing '"
+                    << static_cast<int>(kMaxPixel) << "'";
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void FilterIntraPredTest<bitdepth, Pixel>::TestRandomValues() {
+  // Skip the 'C' test case as this is used as the reference.
+  if (base_filter_intra_pred_ == nullptr) return;
+
+  // Use an alternate seed to differentiate this test from TestSpeed().
+  libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed);
+  for (int i = 0; i < kNumFilterIntraPredictors; ++i) {
+    // It may be worthwhile to temporarily increase this loop size when testing
+    // changes that specifically affect this test.
+    for (int n = 0; n < 10000; ++n) {
+      intra_pred_mem_.Reset(&rnd);
+
+      memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+             sizeof(intra_pred_mem_.dst));
+      const Pixel* const top = intra_pred_mem_.top_mem + 16;
+      const Pixel* const left = intra_pred_mem_.left_mem + 16;
+      const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+      base_filter_intra_pred_(intra_pred_mem_.ref_src, stride, top, left,
+                              static_cast<FilterIntraPredictor>(i),
+                              block_width_, block_height_);
+      cur_filter_intra_pred_(intra_pred_mem_.dst, stride, top, left,
+                             static_cast<FilterIntraPredictor>(i), block_width_,
+                             block_height_);
+      if (!test_utils::CompareBlocks(
+              intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_,
+              block_height_, kMaxBlockSize, kMaxBlockSize, true)) {
+        ADD_FAILURE() << "Result from optimized version of "
+                      << kFilterIntraPredNames[i]
+                      << " differs from reference in iteration #" << n;
+        break;
+      }
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+using FilterIntraPredTest8bpp = FilterIntraPredTest<8, uint8_t>;
+
+const char* const* GetFilterIntraPredDigests8bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumFilterIntraPredictors] = {
+      "a2486efcfb351d60a8941203073e89c6", "240716ae5ecaedc19edae1bdef49e05d",
+      "dacf4af66a966aca7c75abe24cd9ba99", "311888773676f3c2ae3334c4e0f141e5",
+      "2d3711616c8d8798f608e313cb07a72a",
+  };
+  static const char* const kDigests4x8[kNumFilterIntraPredictors] = {
+      "1cb74ba1abc68d936e87c13511ed5fbf", "d64c2c08586a762dbdfa8e1150bede06",
+      "73e9d1a9b6fa3e96fbd65c7dce507529", "e3ae17d9338e5aa3420d31d0e2d7ee87",
+      "750dbfe3bc5508b7031957a1d315b8bc",
+  };
+  static const char* const kDigests4x16[kNumFilterIntraPredictors] = {
+      "48a1060701bf68ec6342d6e24c10ef17", "0c91ff7988814d192ed95e840a87b4bf",
+      "efe586b891c8828c4116c9fbf50850cc", "a3bfa10be2b155826f107e9256ac3ba1",
+      "976273745b94a561fd52f5aa96fb280f",
+  };
+  static const char* const kDigests8x4[kNumFilterIntraPredictors] = {
+      "73f82633aeb28db1d254d077edefd8a9", "8eee505cdb5828e33b67ff5572445dac",
+      "9b0f101c28c66a916079fe5ed33b4021", "47fd44a7e5a5b55f067908192698e25c",
+      "eab59a3710d9bdeca8fa03a15d3f95d6",
+  };
+  static const char* const kDigests8x8[kNumFilterIntraPredictors] = {
+      "aa07b7a007c4c1d494ddb44a23c27bcd", "d27eee43f15dfcfe4c46cd46b681983b",
+      "1015d26022cf57acfdb11fd3f6b9ccb0", "4f0e00ef556fbcac2fb31e3b18869070",
+      "918c2553635763a0756b20154096bca6",
+  };
+  static const char* const kDigests8x16[kNumFilterIntraPredictors] = {
+      "a8ac58b2efb02092035cca206dbf5fbe", "0b22b000b7f124b32545bc86dd9f0142",
+      "cd6a08e023cad301c084b6ec2999da63", "c017f5f4fa5c05e7638ae4db98512b13",
+      "893e6995522e23ed3d613ef3797ca580",
+  };
+  static const char* const kDigests8x32[kNumFilterIntraPredictors] = {
+      "b3d5d4f09b778ae2b8cc0e9014c22320", "e473874a1e65228707489be9ca6477aa",
+      "91bda5a2d32780af345bb3d49324732f", "20f2ff26f004f02e8e2be49e6cadc32f",
+      "00c909b749e36142b133a7357271e83e",
+  };
+  static const char* const kDigests16x4[kNumFilterIntraPredictors] = {
+      "ef252f074fc3f5367748436e676e78ca", "cd436d8803ea40db3a849e7c869855c7",
+      "9cd8601b5d66e61fd002f8b11bfa58d9", "b982f17ee36ef0d1c2cfea20197d5666",
+      "9e350d1cd65d520194281633f566810d",
+  };
+  static const char* const kDigests16x8[kNumFilterIntraPredictors] = {
+      "9a7e0cf9b023a89ee619ee672ba2a219", "c20186bc642912ecd4d48bc4924a79b1",
+      "77de044f4c7f717f947a36fc0aa17946", "3f2fc68f11e6ee0220adb8d1ee085c8e",
+      "2f37e586769dfb88d9d4116b9c28c5ab",
+  };
+  static const char* const kDigests16x16[kNumFilterIntraPredictors] = {
+      "36c5b85b9a6b1d2e8f44f09c81adfe9c", "78494ce3a6a78aa2879ad2e24d43a005",
+      "aa30cd29a74407dbec80161745161eb2", "ae2a0975ef166e05e5e8c3701bd19e93",
+      "6322fba6f3bcb1f6c8e78160d200809c",
+  };
+  static const char* const kDigests16x32[kNumFilterIntraPredictors] = {
+      "82d54732c37424946bc73f5a78f64641", "071773c82869bb103c31e05f14ed3c2f",
+      "3a0094c150bd6e21ce1f17243b21e76b", "998ffef26fc65333ae407bbe9d41a252",
+      "6491add6b665aafc364c8c104a6a233d",
+  };
+  static const char* const kDigests32x8[kNumFilterIntraPredictors] = {
+      "c60062105dd727e94f744c35f0d2156e", "36a9e4d543701c4c546016e35e9c4337",
+      "05a8d07fe271023e63febfb44814d114", "0a28606925519d1ed067d64761619dc8",
+      "bb8c34b143910ba49b01d13e94d936ac",
+  };
+  static const char* const kDigests32x16[kNumFilterIntraPredictors] = {
+      "60e6caeec9194fcb409469e6e1393128", "5d764ead046443eb14f76822a569b056",
+      "b1bf22fcc282614354166fa1eb6e5f8b", "4b188e729fe49ae24100b3ddd8f17313",
+      "75f430fdea0b7b5b66866fd68a795a6a",
+  };
+  static const char* const kDigests32x32[kNumFilterIntraPredictors] = {
+      "5bb91a37b1979866eb23b59dd352229d", "589aa983109500749609d7be1cb79711",
+      "5e8fb1927cdbe21143494b56b5d400f6", "9e28f741d19c64b2a0577d83546d32d9",
+      "73c73237a5d891096066b186abf96854",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(FilterIntraPredTest8bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.5e8 / (block_width_ * block_height_));
+  TestSpeed(GetFilterIntraPredDigests8bpp(tx_size_), num_runs);
+}
+
+TEST_P(FilterIntraPredTest8bpp, FixedInput) {
+  TestSpeed(GetFilterIntraPredDigests8bpp(tx_size_), 1);
+}
+
+TEST_P(FilterIntraPredTest8bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(FilterIntraPredTest8bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using FilterIntraPredTest10bpp = FilterIntraPredTest<10, uint16_t>;
+
+const char* const* GetFilterIntraPredDigests10bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumFilterIntraPredictors] = {
+      "13a9014d9e255cde8e3e85abf6ef5151", "aee33aa3f3baec87a8c019743fff40f1",
+      "fdd8ca2be424501f51fcdb603c2e757c", "aed00c082d1980d4bab45e9318b939f0",
+      "1b363db246aa5400f49479b7d5d41799",
+  };
+  static const char* const kDigests4x8[kNumFilterIntraPredictors] = {
+      "e718b9e31ba3da0392fd4b6cfba5d882", "31ba22989cdc3bb80749685f42c6c697",
+      "6bc5b3a55b94018117569cfdced17bf9", "ec29979fb4936116493dfa1cfc93901c",
+      "c6bcf564e63c42148d9917f089566432",
+  };
+  static const char* const kDigests4x16[kNumFilterIntraPredictors] = {
+      "404bddd88dff2c0414b5398287e54f18", "ff4fb3039cec6c9ffed6d259cbbfd854",
+      "7d6fa3ed9e728ff056a73c40bb6edeb6", "82845d942ad8048578e0037336905146",
+      "f3c07ea65db08c639136a5a9270f95ff",
+  };
+  static const char* const kDigests8x4[kNumFilterIntraPredictors] = {
+      "2008981638f27ba9123973a733e46c3d", "47efecf1f7628cbd8c22e168fcceb5ce",
+      "04c857ffbd1edd6e2788b17410a4a39c", "deb0236c4277b4d7b174fba407e1c9d7",
+      "5b58567f94ae9fa930f700c68c17399d",
+  };
+  static const char* const kDigests8x8[kNumFilterIntraPredictors] = {
+      "d9bab44a6d1373e758bfa0ee88239093", "29b10ddb32d9de2ff0cad6126f010ff6",
+      "1a03f9a18bdbab0811138cd969bf1f93", "e3273c24e77095ffa033a073f5bbcf7b",
+      "5187bb3df943d154cb01fb2f244ff86f",
+  };
+  static const char* const kDigests8x16[kNumFilterIntraPredictors] = {
+      "a2199f792634a56f1c4e88510e408773", "8fd8a98969d19832975ee7131cca9dbb",
+      "d897380941f75b04b1327e63f136d7d6", "d36f52a157027d53b15b7c02a7983436",
+      "0a8c23047b0364f5687b62b01f043359",
+  };
+  static const char* const kDigests8x32[kNumFilterIntraPredictors] = {
+      "5b74ea8e4f60151cf2db9b23d803a2e2", "e0d6bb5fa7d181589c31fcf2755d7c0b",
+      "42e590ffc88b8940b7aade22e13bbb6a", "e47c39ec1761aa7b5a9b1368ede7cfdc",
+      "6e963a89beac6f3a362c269d1017f9a8",
+  };
+  static const char* const kDigests16x4[kNumFilterIntraPredictors] = {
+      "9eaa079622b5dd95ad3a8feb68fa9bbb", "17e3aa6a0034e9eedcfc65b8ce6e7205",
+      "eac5a5337dbaf9bcbc3d320745c8e190", "c6ba9a7e518be04f725bc1dbd399c204",
+      "19020b82ce8bb49a511820c7e1d58e99",
+  };
+  static const char* const kDigests16x8[kNumFilterIntraPredictors] = {
+      "2d2c3255d5dfc1479a5d82a7d5a0d42e", "0fbb4ee851b4ee58c6d30dd820d19e38",
+      "fa77a1b056e8dc8efb702c7832531b32", "186269ca219dc663ad9b4a53e011a54b",
+      "c12180a6dcde0c3579befbb5304ff70b",
+  };
+  static const char* const kDigests16x16[kNumFilterIntraPredictors] = {
+      "dbb81d7ee7d3c83c271400d0160b2e83", "4da656a3ef238d90bb8339471a6fdb7e",
+      "d95006bf299b84a1b04e38d5fa8fb4f7", "742a03331f0fbd66c57df0ae31104aca",
+      "4d20aa440e38b6b7ac83c8c54d313169",
+  };
+  static const char* const kDigests16x32[kNumFilterIntraPredictors] = {
+      "6247730c93789cc25bcb837781dfa05b", "9a93e14b06dd145e35ab21a0353bdebe",
+      "6c5866353e30296a67d9bd7a65d6998d", "389d7f038d7997871745bb1305156ff9",
+      "e7640d81f891e1d06e7da75c6ae74d93",
+  };
+  static const char* const kDigests32x8[kNumFilterIntraPredictors] = {
+      "68f3a603b7c25dd78deffe91aef22834", "48c735e4aa951d6333d99e571bfeadc8",
+      "35239df0993a429fc599a3037c731e4b", "ba7dd72e04af1a1fc1b30784c11df783",
+      "78e9017f7434665d32ec59795aed0012",
+  };
+  static const char* const kDigests32x16[kNumFilterIntraPredictors] = {
+      "8cf2f11f7f77901cb0c522ad191eb998", "204c76d68c5117b89b5c3a05d5548883",
+      "f3751e41e7a595f43d8aaf9a40644e05", "81ea1a7d608d7b91dd3ede0f87e750ee",
+      "b5951334dfbe6229d828e03cd2d98538",
+  };
+  static const char* const kDigests32x32[kNumFilterIntraPredictors] = {
+      "9d8630188c3d1a4f28a6106e343c9380", "c6c92e059faa17163522409b7bf93230",
+      "62e4c959cb06ec661d98769981fbd555", "01e61673f11011571246668e36cc61c5",
+      "4530222ea1de546e202630fcf43f4526",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(FilterIntraPredTest10bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.5e8 / (block_width_ * block_height_));
+  TestSpeed(GetFilterIntraPredDigests10bpp(tx_size_), num_runs);
+}
+
+TEST_P(FilterIntraPredTest10bpp, FixedInput) {
+  TestSpeed(GetFilterIntraPredDigests10bpp(tx_size_), 1);
+}
+
+TEST_P(FilterIntraPredTest10bpp, Overflow) { TestSaturatedValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using FilterIntraPredTest12bpp = FilterIntraPredTest<12, uint16_t>;
+
+const char* const* GetFilterIntraPredDigests12bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumFilterIntraPredictors] = {
+      "27682e2763f742e0c7156a263af54fe1", "f6fe9b73d8a2024b3125d25a42028be3",
+      "8a232b8caa41f8c4f0b547f0aa072fd7", "411b24dc872e91de3a607f18b51c4e34",
+      "9a106b70ca2df5317afc90aba0316a98",
+  };
+  static const char* const kDigests4x8[kNumFilterIntraPredictors] = {
+      "a0d3f3a8f498727af0844a6df90da971", "bb02998e3d5d7b4643db616a5ce75c51",
+      "eaa39425427c155dea1836c37fc14f7e", "747cc4fa0c9e3418f4a15ded9f846599",
+      "c1a2aeaa01dd3edac4c26f74e01d8d57",
+  };
+  static const char* const kDigests4x16[kNumFilterIntraPredictors] = {
+      "80c01fdef14e3db28987e323801c998e", "de5a2f59384a096324eebe843d4b8ba5",
+      "f85e18efc9297793392607cdd84d8bc4", "d84bf2d9d4996c2f7fd82b6bbd52577b",
+      "9d73771de09c17bd494f1f5f75ab1111",
+  };
+  static const char* const kDigests8x4[kNumFilterIntraPredictors] = {
+      "7df2b038c4d816eb4949de6b933f0632", "0f1c45dd6e8d5534de0c9a279087ea8b",
+      "1b79f3b10facd9ffc404cbafdd73aa43", "e19adec4f14d72c5157f9faf7fc9b23e",
+      "a30ed988ea6ed797d4bf0945ffe7e330",
+  };
+  static const char* const kDigests8x8[kNumFilterIntraPredictors] = {
+      "097a0c14d89ece69e779fa755a2b75c0", "ebadfc559b20246dcd8d74413ff4d088",
+      "097c91bedc1e703b3eb54361d94df59a", "765bbad37b91e644292beac5f06811be",
+      "f3c809461fa3325f0d33087ca79c47d0",
+  };
+  static const char* const kDigests8x16[kNumFilterIntraPredictors] = {
+      "36464af48b38005b61f7f528a0b0c8ba", "47fa0868224c71d28d3cdcf247282c13",
+      "ca34bb57a37ee3e5428814ec63f52117", "420bdca6b643f4421d465345cc264167",
+      "339c124c07a611a65952dc9996ba6e12",
+  };
+  static const char* const kDigests8x32[kNumFilterIntraPredictors] = {
+      "99ca0d3b3fbdd4661a2c07bdb2752a70", "6fedae1dbfe721210b65e08dc77847dd",
+      "956810089f81dc9334103111afec2fbb", "ede4f0bee06def6d8a2037939415d845",
+      "ca146dfe0edbdac3066a0ca387fb6277",
+  };
+  static const char* const kDigests16x4[kNumFilterIntraPredictors] = {
+      "b0f7d5dbf7f9aa3f0ab13273de80dc9d", "a3537f2b60426e9f83aeef973161fcfd",
+      "d4f868f793ab232bee17b49afcfc28a0", "fc43429761d10723b5f377eb6513e59a",
+      "f59aabb06574ce24e1d1113753edb098",
+  };
+  static const char* const kDigests16x8[kNumFilterIntraPredictors] = {
+      "0b539f1e2ecf0300bf3838ab1d80952c", "44f01a4324cda8d27ea44a8bd3620526",
+      "a57819a22b422e7da9d85f09504a2c57", "dbff6a417a8f3606575acb3c98efe091",
+      "534e8e8cd4b73cb4f6ec22f903727efa",
+  };
+  static const char* const kDigests16x16[kNumFilterIntraPredictors] = {
+      "247192bd6a5c2821b8694e4669361103", "1935044a6220ac6315a58b402465b6da",
+      "bdce29a3e988b804d429da1446a34c2a", "4697132c20395fabac2662cb8b1ce35a",
+      "3d07a7beaff6925175fcd9a8e69542e6",
+  };
+  static const char* const kDigests16x32[kNumFilterIntraPredictors] = {
+      "3429b83b7ba723bdd2e3e368979b51b0", "cd099d0eb7f4a20547f91d9402e3394a",
+      "a6a7cc4e0f8ed34424264107b3657fb8", "0125ace62bec7c7ff7240bf5b6f689c5",
+      "a0722dba921b078a6d569ecb81777bf8",
+  };
+  static const char* const kDigests32x8[kNumFilterIntraPredictors] = {
+      "44b1b086ee37a93406e5db95dca825d7", "fdeed5c4644dc288f6dcc148e8d2867a",
+      "b241d112f6fa7a24c44706fb76e49132", "a782dcf01a16231276dbd20121bad640",
+      "4da9c0efd0bcb31f911af52779317fb9",
+  };
+  static const char* const kDigests32x16[kNumFilterIntraPredictors] = {
+      "bf9704995a0a868c45280cac3415c0a7", "373626072ade7c8d709ab732149fd3ae",
+      "9e4a2062aa86ac8dc5164002c953c7ca", "62eede30996d0e55afcf513fe9ad3c58",
+      "a5f3bb32688d5189341304d12e4e6449",
+  };
+  static const char* const kDigests32x32[kNumFilterIntraPredictors] = {
+      "bd93c4ddbe0f06e3f12be25ce490f68c", "bfe772b203b83c982f35a8ed0682cd16",
+      "d357ae05ce215f4c5af650ae82909081", "bd640d3c511edaac1753b64c81afb75d",
+      "4d05d67e02a7c4af7ae981b0eb8a4d7b",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(FilterIntraPredTest12bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.5e8 / (block_width_ * block_height_));
+  TestSpeed(GetFilterIntraPredDigests12bpp(tx_size_), num_runs);
+}
+
+TEST_P(FilterIntraPredTest12bpp, FixedInput) {
+  TestSpeed(GetFilterIntraPredDigests12bpp(tx_size_), 1);
+}
+
+TEST_P(FilterIntraPredTest12bpp, Overflow) { TestSaturatedValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+// Filter-intra and Cfl predictors are available only for transform sizes
+// with max(width, height) <= 32.
+constexpr TransformSize kTransformSizesSmallerThan32x32[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize32x8,
+    kTransformSize32x16, kTransformSize32x32};
+
+INSTANTIATE_TEST_SUITE_P(C, FilterIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, FilterIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, FilterIntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, FilterIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, FilterIntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_ENABLE_NEON
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, FilterIntraPredTest12bpp,
+                         testing::ValuesIn(kTransformSizesSmallerThan32x32));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const TransformSize tx_size) {
+  return os << ToString(tx_size);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/intrapred_test.cc b/src/dsp/intrapred_test.cc
new file mode 100644
index 0000000..cca1c73
--- /dev/null
+++ b/src/dsp/intrapred_test.cc
@@ -0,0 +1,914 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/intrapred.h"
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/dsp/intrapred_smooth.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockSize = 64;
+constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
+
+template <int bitdepth, typename Pixel>
+class IntraPredTestBase : public testing::TestWithParam<TransformSize>,
+                          public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraPredTestBase() {
+    switch (tx_size_) {
+      case kNumTransformSizes:
+        EXPECT_NE(tx_size_, kNumTransformSizes);
+        break;
+      default:
+        block_width_ = kTransformWidth[tx_size_];
+        block_height_ = kTransformHeight[tx_size_];
+        break;
+    }
+  }
+
+  IntraPredTestBase(const IntraPredTestBase&) = delete;
+  IntraPredTestBase& operator=(const IntraPredTestBase&) = delete;
+  ~IntraPredTestBase() override = default;
+
+ protected:
+  struct IntraPredMem {
+    void Reset(libvpx_test::ACMRandom* rnd) {
+      ASSERT_NE(rnd, nullptr);
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      const int mask = (1 << bitdepth) - 1;
+      for (auto& r : ref_src) r = rnd->Rand16() & mask;
+      for (int i = 0; i < kMaxBlockSize; ++i) left[i] = rnd->Rand16() & mask;
+      for (int i = -1; i < kMaxBlockSize; ++i) top[i] = rnd->Rand16() & mask;
+
+      // Some directional predictors require top-right, bottom-left.
+      for (int i = kMaxBlockSize; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = rnd->Rand16() & mask;
+        top[i] = rnd->Rand16() & mask;
+      }
+      // TODO(jzern): reorder this and regenerate the digests after switching
+      // random number generators.
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      left[-1] = rnd->Rand16() & mask;
+      left[-2] = rnd->Rand16() & mask;
+      top[-2] = rnd->Rand16() & mask;
+      memset(left_mem, 0, sizeof(left_mem[0]) * 14);
+      memset(top_mem, 0, sizeof(top_mem[0]) * 14);
+      memset(top_mem + kMaxBlockSize * 2 + 16, 0,
+             sizeof(top_mem[0]) * kTopMemPadding);
+    }
+
+    // Set ref_src, top-left, top and left to |pixel|.
+    void Set(const Pixel pixel) {
+      Pixel* const left = left_mem + 16;
+      Pixel* const top = top_mem + 16;
+      for (auto& r : ref_src) r = pixel;
+      // Upsampling in the directional predictors extends left/top[-1] to [-2].
+      for (int i = -2; i < 2 * kMaxBlockSize; ++i) {
+        left[i] = top[i] = pixel;
+      }
+    }
+
+    // DirectionalZone1_Large() overreads up to 7 pixels in |top_mem|.
+    static constexpr int kTopMemPadding = 7;
+    alignas(kMaxAlignment) Pixel dst[kTotalPixels];
+    alignas(kMaxAlignment) Pixel ref_src[kTotalPixels];
+    alignas(kMaxAlignment) Pixel left_mem[kMaxBlockSize * 2 + 16];
+    alignas(
+        kMaxAlignment) Pixel top_mem[kMaxBlockSize * 2 + 16 + kTopMemPadding];
+  };
+
+  void SetUp() override { test_utils::ResetDspTable(bitdepth); }
+
+  const TransformSize tx_size_ = GetParam();
+  int block_width_;
+  int block_height_;
+  IntraPredMem intra_pred_mem_;
+};
+
+//------------------------------------------------------------------------------
+// IntraPredTest
+
+template <int bitdepth, typename Pixel>
+class IntraPredTest : public IntraPredTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  IntraPredTest() = default;
+  IntraPredTest(const IntraPredTest&) = delete;
+  IntraPredTest& operator=(const IntraPredTest&) = delete;
+  ~IntraPredTest() override = default;
+
+ protected:
+  using IntraPredTestBase<bitdepth, Pixel>::tx_size_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_width_;
+  using IntraPredTestBase<bitdepth, Pixel>::block_height_;
+  using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_;
+
+  void SetUp() override {
+    IntraPredTestBase<bitdepth, Pixel>::SetUp();
+    IntraPredInit_C();
+    IntraPredSmoothInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    memcpy(base_intrapreds_, dsp->intra_predictors[tx_size_],
+           sizeof(base_intrapreds_));
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      memset(base_intrapreds_, 0, sizeof(base_intrapreds_));
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        IntraPredInit_SSE4_1();
+        IntraPredSmoothInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      IntraPredInit_NEON();
+      IntraPredSmoothInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    memcpy(cur_intrapreds_, dsp->intra_predictors[tx_size_],
+           sizeof(cur_intrapreds_));
+
+    for (int i = 0; i < kNumIntraPredictors; ++i) {
+      // skip functions that haven't been specialized for this particular
+      // architecture.
+      if (cur_intrapreds_[i] == base_intrapreds_[i]) {
+        cur_intrapreds_[i] = nullptr;
+      }
+    }
+  }
+
+  // These tests modify intra_pred_mem_.
+  void TestSpeed(const char* const digests[kNumIntraPredictors], int num_runs);
+  void TestSaturatedValues();
+  void TestRandomValues();
+
+  IntraPredictorFunc base_intrapreds_[kNumIntraPredictors];
+  IntraPredictorFunc cur_intrapreds_[kNumIntraPredictors];
+};
+
+template <int bitdepth, typename Pixel>
+void IntraPredTest<bitdepth, Pixel>::TestSpeed(
+    const char* const digests[kNumIntraPredictors], const int num_runs) {
+  ASSERT_NE(digests, nullptr);
+  const auto* const left =
+      reinterpret_cast<const uint8_t*>(intra_pred_mem_.left_mem + 16);
+  const auto* const top =
+      reinterpret_cast<const uint8_t*>(intra_pred_mem_.top_mem + 16);
+
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  intra_pred_mem_.Reset(&rnd);
+
+  for (int i = 0; i < kNumIntraPredictors; ++i) {
+    if (cur_intrapreds_[i] == nullptr) continue;
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const absl::Time start = absl::Now();
+    for (int run = 0; run < num_runs; ++run) {
+      const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+      cur_intrapreds_[i](intra_pred_mem_.dst, stride, top, left);
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    test_utils::CheckMd5Digest(ToString(tx_size_),
+                               ToString(static_cast<IntraPredictor>(i)),
+                               digests[i], intra_pred_mem_.dst,
+                               sizeof(intra_pred_mem_.dst), elapsed_time);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void IntraPredTest<bitdepth, Pixel>::TestSaturatedValues() {
+  Pixel* const left = intra_pred_mem_.left_mem + 16;
+  Pixel* const top = intra_pred_mem_.top_mem + 16;
+  const auto kMaxPixel = static_cast<Pixel>((1 << bitdepth) - 1);
+  intra_pred_mem_.Set(kMaxPixel);
+
+  // skip DcFill
+  for (int i = 1; i < kNumIntraPredictors; ++i) {
+    if (cur_intrapreds_[i] == nullptr) continue;
+    memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+           sizeof(intra_pred_mem_.dst));
+    const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+    cur_intrapreds_[i](intra_pred_mem_.dst, stride, top, left);
+    if (!test_utils::CompareBlocks(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+                                   block_width_, block_height_, kMaxBlockSize,
+                                   kMaxBlockSize, true)) {
+      ADD_FAILURE() << "Expected " << ToString(static_cast<IntraPredictor>(i))
+                    << " to produce a block containing '"
+                    << static_cast<int>(kMaxPixel) << "'";
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void IntraPredTest<bitdepth, Pixel>::TestRandomValues() {
+  // Use an alternate seed to differentiate this test from TestSpeed().
+  libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed);
+  for (int i = 0; i < kNumIntraPredictors; ++i) {
+    // Skip the 'C' test case as this is used as the reference.
+    if (base_intrapreds_[i] == nullptr) continue;
+    if (cur_intrapreds_[i] == nullptr) continue;
+    // It may be worthwhile to temporarily increase this loop size when testing
+    // changes that specifically affect this test.
+    for (int n = 0; n < 10000; ++n) {
+      intra_pred_mem_.Reset(&rnd);
+
+      memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src,
+             sizeof(intra_pred_mem_.dst));
+      const Pixel* const top = intra_pred_mem_.top_mem + 16;
+      const Pixel* const left = intra_pred_mem_.left_mem + 16;
+      const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel);
+      base_intrapreds_[i](intra_pred_mem_.ref_src, stride, top, left);
+      cur_intrapreds_[i](intra_pred_mem_.dst, stride, top, left);
+      if (!test_utils::CompareBlocks(
+              intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_,
+              block_height_, kMaxBlockSize, kMaxBlockSize, true)) {
+        ADD_FAILURE() << "Result from optimized version of "
+                      << ToString(static_cast<IntraPredictor>(i))
+                      << " differs from reference in iteration #" << n;
+        break;
+      }
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+
+using IntraPredTest8bpp = IntraPredTest<8, uint8_t>;
+
+const char* const* GetIntraPredDigests8bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumIntraPredictors] = {
+      "7b1c762e28747f885d2b7d83cb8aa75c", "73353f179207f1432d40a132809e3a50",
+      "80c9237c838b0ec0674ccb070df633d5", "1cd79116b41fda884e7fa047f5eb14df",
+      "33211425772ee539a59981a2e9dc10c1", "d6f5f65a267f0e9a2752e8151cc1dcd7",
+      "7ff8c762cb766eb0665682152102ce4b", "2276b861ae4599de15938651961907ec",
+      "766982bc69f4aaaa8e71014c2dc219bc", "e2c31b5fd2199c49e17c31610339ab3f",
+  };
+  static const char* const kDigests4x8[kNumIntraPredictors] = {
+      "0a0d8641ecfa0e82f541acdc894d5574", "1a40371af6cff9c278c5b0def9e4b3e7",
+      "3631a7a99569663b514f15b590523822", "646c7b592136285bd31501494e7393e7",
+      "ecbe89cc64dc2688123d3cfe865b5237", "79048e70ecbb7d43a4703f62718588c0",
+      "f3de11bf1198a00675d806d29c41d676", "32bb6cd018f6e871c342fcc21c7180cf",
+      "6f076a1e5ab3d69cf08811d62293e4be", "2a84460a8b189b4589824cf6b3b39954",
+  };
+  static const char* const kDigests4x16[kNumIntraPredictors] = {
+      "cb8240be98444ede5ae98ca94afc1557", "460acbcf825a1fa0d8f2aa6bf2d6a21c",
+      "7896fdbbfe538dce1dc3a5b0873d74b0", "504aea29c6b27f21555d5516b8de2d8a",
+      "c5738e7fa82b91ea0e39232120da56ea", "19abbd934c243a6d9df7585d81332dd5",
+      "9e42b7b342e45c842dfa8aedaddbdfaa", "0e9eb07a89f8bf96bc219d5d1c3d9f6d",
+      "659393c31633e0f498bae384c9df5c7b", "bee3a28312da99dd550ec309ae4fff25",
+  };
+  static const char* const kDigests8x4[kNumIntraPredictors] = {
+      "5950744064518f77867c8e14ebd8b5d7", "46b6cbdc76efd03f4ac77870d54739f7",
+      "efe21fd1b98cb1663950e0bf49483b3b", "3c647b64760b298092cbb8e2f5c06bfd",
+      "c3595929687ffb04c59b128d56e2632f", "d89ad2ddf8a74a520fdd1d7019fd75b4",
+      "53907cb70ad597ee5885f6c58201f98b", "09d2282a29008b7fb47eb60ed6653d06",
+      "e341fc1c910d7cb2dac5dbc58b9c9af9", "a8fabd4c259b607a90a2e4d18cae49de",
+  };
+  static const char* const kDigests8x8[kNumIntraPredictors] = {
+      "06fb7cb52719855a38b4883b4b241749", "2013aafd42a4303efb553e42264ab8b0",
+      "2f070511d5680c12ca73a20e47fd6e23", "9923705af63e454392625794d5459fe0",
+      "04007a0d39778621266e2208a22c4fac", "2d296c202d36b4a53f1eaddda274e4a1",
+      "c87806c220d125c7563c2928e836fbbd", "339b49710a0099087e51ab5afc8d8713",
+      "c90fbc020afd9327bf35dccae099bf77", "95b356a7c346334d29294a5e2d13cfd9",
+  };
+  static const char* const kDigests8x16[kNumIntraPredictors] = {
+      "3c5a4574d96b5bb1013429636554e761", "8cf56b17c52d25eb785685f2ab48b194",
+      "7911e2e02abfbe226f17529ac5db08fc", "064e509948982f66a14293f406d88d42",
+      "5c443aa713891406d5be3af4b3cf67c6", "5d2cb98e532822ca701110cda9ada968",
+      "3d58836e17918b8890012dd96b95bb9d", "20e8d61ddc451b9e553a294073349ffd",
+      "a9aa6cf9d0dcf1977a1853ccc264e40b", "103859f85750153f47b81f68ab7881f2",
+  };
+  static const char* const kDigests8x32[kNumIntraPredictors] = {
+      "b393a2db7a76acaccc39e04d9dc3e8ac", "bbda713ee075a7ef095f0f479b5a1f82",
+      "f337dce3980f70730d6f6c2c756e3b62", "796189b05dc026e865c9e95491b255d1",
+      "ea932c21e7189eeb215c1990491320ab", "a9fffdf9455eba5e3b01317cae140289",
+      "9525dbfdbf5fba61ef9c7aa5fe887503", "8c6a7e3717ff8a459f415c79bb17341c",
+      "3761071bfaa2363a315fe07223f95a2d", "0e5aeb9b3f485b90df750469f60c15aa",
+  };
+  static const char* const kDigests16x4[kNumIntraPredictors] = {
+      "1c0a950b3ac500def73b165b6a38467c", "95e7f7300f19da280c6a506e40304462",
+      "28a6af15e31f76d3ff189012475d78f5", "e330d67b859bceef62b96fc9e1f49a34",
+      "36eca3b8083ce2fb5f7e6227dfc34e71", "08f567d2abaa8e83e4d9b33b3f709538",
+      "dc2d0ba13aa9369446932f03b53dc77d", "9ab342944c4b1357aa79d39d7bebdd3a",
+      "77ec278c5086c88b91d68eef561ed517", "60fbe11bfe216c182aaacdec326c4dae",
+  };
+  static const char* const kDigests16x8[kNumIntraPredictors] = {
+      "053a2bc4b5b7287fee524af4e77f077a", "619b720b13f14f32391a99ea7ff550d5",
+      "728d61c11b06baf7fe77881003a918b9", "889997b89a44c9976cb34f573e2b1eea",
+      "b43bfc31d1c770bb9ca5ca158c9beec4", "9d3fe9f762e0c6e4f114042147c50c7f",
+      "c74fdd7c9938603b01e7ecf9fdf08d61", "870c7336db1102f80f74526bd5a7cf4e",
+      "3fd5354a6190903d6a0b661fe177daf6", "409ca6b0b2558aeadf5ef2b8a887e67a",
+  };
+  static const char* const kDigests16x16[kNumIntraPredictors] = {
+      "1fa9e2086f6594bda60c30384fbf1635", "2098d2a030cd7c6be613edc74dc2faf8",
+      "f3c72b0c8e73f1ddca04d14f52d194d8", "6b31f2ee24cf88d3844a2fc67e1f39f3",
+      "d91a22a83575e9359c5e4871ab30ddca", "24c32a0d38b4413d2ef9bf1f842c8634",
+      "6e9e47bf9da9b2b9ae293e0bbd8ff086", "968b82804b5200b074bcdba9718140d4",
+      "4e6d7e612c5ae0bbdcc51a453cd1db3f", "ce763a41977647d072f33e277d69c7b9",
+  };
+  static const char* const kDigests16x32[kNumIntraPredictors] = {
+      "01afd04432026ff56327d6226b720be2", "a6e7be906cc6f1e7a520151bfa7c303d",
+      "bc05c46f18d0638f0228f1de64f07cd5", "204e613e429935f721a5b29cec7d44bb",
+      "aa0a7c9a7482dfc06d9685072fc5bafd", "ffb60f090d83c624bb4f7dc3a630ac4f",
+      "36bcb9ca9bb5eac520b050409de25da5", "34d9a5dd3363668391bc3bd05b468182",
+      "1e149c28db8b234e43931c347a523794", "6e8aff02470f177c3ff4416db79fc508",
+  };
+  static const char* const kDigests16x64[kNumIntraPredictors] = {
+      "727797ef15ccd8d325476fe8f12006a3", "f77c544ac8035e01920deae40cee7b07",
+      "12b0c69595328c465e0b25e0c9e3e9fc", "3b2a053ee8b05a8ac35ad23b0422a151",
+      "f3be77c0fe67eb5d9d515e92bec21eb7", "f1ece6409e01e9dd98b800d49628247d",
+      "efd2ec9bfbbd4fd1f6604ea369df1894", "ec703de918422b9e03197ba0ed60a199",
+      "739418efb89c07f700895deaa5d0b3e3", "9943ae1bbeeebfe1d3a92dc39e049d63",
+  };
+  static const char* const kDigests32x8[kNumIntraPredictors] = {
+      "4da55401331ed98acec0c516d7307513", "0ae6f3974701a5e6c20baccd26b4ca52",
+      "79b799f1eb77d5189535dc4e18873a0e", "90e943adf3de4f913864dce4e52b4894",
+      "5e1b9cc800a89ef45f5bdcc9e99e4e96", "3103405df20d254cbf32ac30872ead4b",
+      "648550e369b77687bff3c7d6f249b02f", "f9f73bcd8aadfc059fa260325df957a1",
+      "204cef70d741c25d4fe2b1d10d2649a5", "04c05e18488496eba64100faa25e8baf",
+  };
+  static const char* const kDigests32x16[kNumIntraPredictors] = {
+      "86ad1e1047abaf9959150222e8f19593", "1908cbe04eb4e5c9d35f1af7ffd7ee72",
+      "6ad3bb37ebe8374b0a4c2d18fe3ebb6a", "08d3cfe7a1148bff55eb6166da3378c6",
+      "656a722394764d17b6c42401b9e0ad3b", "4aa00c192102efeb325883737e562f0d",
+      "9881a90ca88bca4297073e60b3bb771a", "8cd74aada398a3d770fc3ace38ecd311",
+      "0a927e3f5ff8e8338984172cc0653b13", "d881d68b4eb3ee844e35e04ad6721f5f",
+  };
+  static const char* const kDigests32x32[kNumIntraPredictors] = {
+      "1303ca680644e3d8c9ffd4185bb2835b", "2a4d9f5cc8da307d4cf7dc021df10ba9",
+      "ced60d3f4e4b011a6a0314dd8a4b1fd8", "ced60d3f4e4b011a6a0314dd8a4b1fd8",
+      "1464b01aa928e9bd82c66bad0f921693", "90deadfb13d7c3b855ba21b326c1e202",
+      "af96a74f8033dff010e53a8521bc6f63", "9f1039f2ef082aaee69fcb7d749037c2",
+      "3f82893e478e204f2d254b34222d14dc", "ddb2b95ffb65b84dd4ff1f7256223305",
+  };
+  static const char* const kDigests32x64[kNumIntraPredictors] = {
+      "e1e8ed803236367821981500a3d9eebe", "0f46d124ba9f48cdd5d5290acf786d6d",
+      "4e2a2cfd8f56f15939bdfc753145b303", "0ce332b343934b34cd4417725faa85cb",
+      "1d2f8e48e3adb7c448be05d9f66f4954", "9fb2e176636a5689b26f73ca73fcc512",
+      "e720ebccae7e25e36f23da53ae5b5d6a", "86fe4364734169aaa4520d799890d530",
+      "b1870290764bb1b100d1974e2bd70f1d", "ce5b238e19d85ef69d85badfab4e63ae",
+  };
+  static const char* const kDigests64x16[kNumIntraPredictors] = {
+      "de1b736e9d99129609d6ef3a491507a0", "516d8f6eb054d74d150e7b444185b6b9",
+      "69e462c3338a9aaf993c3f7cfbc15649", "821b76b1494d4f84d20817840f719a1a",
+      "fd9b4276e7affe1e0e4ce4f428058994", "cd82fd361a4767ac29a9f406b480b8f3",
+      "2792c2f810157a4a6cb13c28529ff779", "1220442d90c4255ba0969d28b91e93a6",
+      "c7253e10b45f7f67dfee3256c9b94825", "879792198071c7e0b50b9b5010d8c18f",
+  };
+  static const char* const kDigests64x32[kNumIntraPredictors] = {
+      "e48e1ac15e97191a8fda08d62fff343e", "80c15b303235f9bc2259027bb92dfdc4",
+      "538424b24bd0830f21788e7238ca762f", "a6c5aeb722615089efbca80b02951ceb",
+      "12604b37875533665078405ef4582e35", "0048afa17bd3e1632d68b96048836530",
+      "07a0cfcb56a5eed50c4bd6c26814336b", "529d8a070de5bc6531fa3ee8f450c233",
+      "33c50a11c7d78f72434064f634305e95", "e0ef7f0559c1a50ec5a8c12011b962f7",
+  };
+  static const char* const kDigests64x64[kNumIntraPredictors] = {
+      "a1650dbcd56e10288c3e269eca37967d", "be91585259bc37bf4dc1651936e90b3e",
+      "afe020786b83b793c2bbd9468097ff6e", "6e1094fa7b50bc813aa2ba29f5df8755",
+      "9e5c34f3797e0cdd3cd9d4c05b0d8950", "bc87be7ac899cc6a28f399d7516c49fe",
+      "9811fd0d2dd515f06122f5d1bd18b784", "3c140e466f2c2c0d9cb7d2157ab8dc27",
+      "9543de76c925a8f6adc884cc7f98dc91", "df1df0376cc944afe7e74e94f53e575a",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(IntraPredTest8bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetIntraPredDigests8bpp(tx_size_), num_runs);
+}
+
+TEST_P(IntraPredTest8bpp, FixedInput) {
+  TestSpeed(GetIntraPredDigests8bpp(tx_size_), 1);
+}
+
+TEST_P(IntraPredTest8bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(IntraPredTest8bpp, Random) { TestRandomValues(); }
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using IntraPredTest10bpp = IntraPredTest<10, uint16_t>;
+
+const char* const* GetIntraPredDigests10bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumIntraPredictors] = {
+      "432bf9e762416bec582cb3654cbc4545", "8b9707ff4d506e0cb326f2d9a8d78705",
+      "a076275258cc5af87ed8b075136fb219", "f9587004012a8d2cecaa347331ccdf96",
+      "1c4e6890c5e6eed495fe54a6b6df8d6f", "0ae15fae8969a3c972ee895f325955a3",
+      "97db177738b831da8066df4f3fb7adbd", "4add5685b8a56991c9dce4ff7086ec25",
+      "75c6a655256188e378e70658b8f1631f", "14a27db20f9d5594ef74a7ea10c3e5ef",
+  };
+  static const char* const kDigests4x8[kNumIntraPredictors] = {
+      "9cbd7c18aca2737fa41db27150798819", "13d1e734692e27339c10b07da33c1113",
+      "0617cf74e2dd5d34ea517af1767fa47e", "c6a7b01228ccdf74af8528ef8f5f55c6",
+      "13b05d87b3d566b2f7a4b332cd8a762e", "b26ae0e8da1fe8989dfe2900fa2c3847",
+      "c30f3acdd386bdac91028fe48b751810", "04d2baf5192c5af97ca18d3b9b0d5968",
+      "a0ef82983822fc815bf1e8326cd41e33", "20bf218bae5f6b5c6d56b85f3f9bbadb",
+  };
+  static const char* const kDigests4x16[kNumIntraPredictors] = {
+      "d9b47bdddaa5e22312ff9ece7a3cae08", "cb76c79971b502dd8999a7047b3e2f86",
+      "3b09a3ff431d03b379acfdc444602540", "88608f6fcd687831e871053723cf76c3",
+      "a7bd2a17de1cf19c9a4b2c550f277a5c", "29b389f564f266a67687b8d2bc750418",
+      "4680847c30fe93c06f87e2ee1da544d6", "0e4eda11e1fe6ebe8526c2a2c5390bbb",
+      "bf3e20197282885acabb158f3a77ba59", "fccea71d1a253316b905f4a073c84a36",
+  };
+  static const char* const kDigests8x4[kNumIntraPredictors] = {
+      "05ba0ed96aac48cd94e7597f12184320", "d97d04e791904d3cedc34d5430a4d1d2",
+      "49217081a169c2d30b0a43f816d0b58b", "09e2a6a6bfe35b83e9434ee9c8dcf417",
+      "4b03c8822169ee4fa058513d65f0e32f", "cabdeebc923837ee3f2d3480354d6a81",
+      "957eda610a23a011ed25976aee94eaf0", "4a197e3dfce1f0d3870138a9b66423aa",
+      "18c0d0fbe0e96a0baf2f98fa1908cbb9", "21114e5737328cdbba9940e4f85a0855",
+  };
+  static const char* const kDigests8x8[kNumIntraPredictors] = {
+      "430e99eecda7e6434e1973dbdcc2a29d", "88864d7402c09b57735db49c58707304",
+      "8312f80b936380ceb51375e29a4fd75d", "472a7ed9c68bdbd9ecca197b7a8b3f01",
+      "4f66ee4dc0cb752c3b65d576cd06bb5c", "36383d6f61799143470129e2d5241a6f",
+      "c96279406c8d2d02771903e93a4e8d37", "4fb64f9700ed0bf08fbe7ab958535348",
+      "c008c33453ac9cf8c42ae6ec88f9941c", "39c401a9938b23e318ae7819e458daf1",
+  };
+  static const char* const kDigests8x16[kNumIntraPredictors] = {
+      "bda6b75fedfe0705f9732ff84c918672", "4ff130a47429e0762386557018ec10b2",
+      "8156557bf938d8e3a266318e57048fc5", "bdfa8e01a825ec7ae2d80519e3c94eec",
+      "108fc8e5608fe09f9cc30d7a52cbc0c1", "a2271660af5424b64c6399ca5509dee1",
+      "b09af9729f39516b28ff62363f8c0cb2", "4fe67869dac99048dfcf4d4e621884ec",
+      "311f498369a9c98f77a961bf91e73e65", "d66e78b9f41d5ee6a4b25e37ec9af324",
+  };
+  static const char* const kDigests8x32[kNumIntraPredictors] = {
+      "26c45325f02521e7e5c66c0aa0819329", "79dfb68513d4ccd2530c485f0367858e",
+      "8288e99b4d738b13956882c3ad3f03fe", "7c4993518b1620b8be8872581bb72239",
+      "2b1c3126012d981f787ed0a2601ee377", "051ba9f0c4d4fecb1fcd81fdea94cae4",
+      "320362239ad402087303a4df39512bb1", "210df35b2055c9c01b9e3e5ae24e524b",
+      "f8536db74ce68c0081bbd8799dac25f9", "27f2fe316854282579906d071af6b705",
+  };
+  static const char* const kDigests16x4[kNumIntraPredictors] = {
+      "decff67721ff7e9e65ec641e78f5ccf3", "99e3b2fbdabfa9b76b749cfb6530a9fd",
+      "accdb3d25629916963a069f1e1c0e061", "ad42855e9146748b0e235b8428487b4b",
+      "53025e465f267e7af2896ebd028447a0", "577d26fcd2d655cc77a1f1f875648699",
+      "7a61a3619267221b448b20723840e9f0", "fb4ccc569bdae3614e87bc5be1e84284",
+      "b866095d8a3e6910cc4f92f8d8d6075a", "6ba9013cba1624872bfbac111e8d344a",
+  };
+  static const char* const kDigests16x8[kNumIntraPredictors] = {
+      "2832156bd076c75f8be5622f34cb3efe", "da70e516f5a8842dd4965b80cd8d2a76",
+      "c3e137c6d79c57be2073d1eda22c8d1e", "8c5d28c7b3301b50326582dd7f89a175",
+      "9d8558775155b201cd178ab61458b642", "ecbddb9c6808e0c609c8fe537b7f7408",
+      "29a123c22cb4020170f9a80edf1208da", "653d0cd0688aa682334156f7b4599b34",
+      "1bfa66ae92a22a0346511db1713fe7df", "1802ad1e657e7fc08fc063342f471ca1",
+  };
+  static const char* const kDigests16x16[kNumIntraPredictors] = {
+      "2270c626de9d49769660ae9184a6428f", "9f069625cdcdd856e2e7ec19ff4fcd50",
+      "34167b9c413362a377aa7b1faf92ae6d", "3cec2b23d179765daea8dfb87c9efdd5",
+      "daa8f0863a5df2aef2b20999961cc8f8", "d9e4dd4bc63991e4f09cb97eb25f4db4",
+      "4e1a182fc3fcf5b9f5a73898f81c2004", "c58e4275406c9fd1c2a74b40c27afff0",
+      "b8092796fd4e4dd9d2b92afb770129ba", "75424d1f18ff00c4093743d033c6c9b6",
+  };
+  static const char* const kDigests16x32[kNumIntraPredictors] = {
+      "5aa050947f3d488537f5a68c23bb135b", "9e66143a2c3863b6fe171275a192d378",
+      "86b0c4777625e84d52913073d234f860", "9e2144fcf2107c76cec4241416bbecd5",
+      "c72be592efc72c3c86f2359b6f622aba", "c4e0e735545f78f43e21e9c39eab7b8f",
+      "52122e7c84a4bab67a8a359efb427023", "7b5fd8bb7e0744e81fd6fa4ed4c2e0fb",
+      "a9950d110bffb0411a8fcd1262dceef0", "2a2dd496f01f5d87f257ed202a703cbe",
+  };
+  static const char* const kDigests16x64[kNumIntraPredictors] = {
+      "eeb1b873e81ca428b11f162bd5b28843", "39ce7d22791f82562b0ca1e0afdf1604",
+      "6bd6bdac8982a4b84613f9963d35d5e9", "a9ac2438e87522621c7e6fe6d02c01ab",
+      "a8b9c471fe6c66ed0717e77fea77bba1", "e050b6aa38aee6e951d3be5a94a8abd0",
+      "3c5ecc31aa45e8175d37e90af247bca6", "30c0f9e412ea726970f575f910edfb94",
+      "f3d96395816ce58fb98480a5b4c32ab2", "9c14811957e013fb009dcd4a3716b338",
+  };
+  static const char* const kDigests32x8[kNumIntraPredictors] = {
+      "d6560d7fc9ae9bd7c25e2983b4a825e3", "90a67154bbdc26cd06ab0fa25fff3c53",
+      "c42d37c5a634e68fafc982626842db0b", "ecc8646d258cfa431facbc0dba168f80",
+      "9f3c167b790b52242dc8686c68eac389", "62dc3bc34406636ccec0941579461f65",
+      "5c0f0ebdb3c936d4decc40d5261aec7c", "dbfc0f056ca25e0331042da6d292e10a",
+      "14fa525d74e6774781198418d505c595", "5f95e70db03da9ed70cd79e23f19199c",
+  };
+  static const char* const kDigests32x16[kNumIntraPredictors] = {
+      "dfe3630aa9eeb1adcc8604269a309f26", "ba6180227d09f5a573f69dc6ee1faf80",
+      "03edea9d71ca3d588e1a0a69aecdf555", "2c8805415f44b4fac6692090dc1b1ddd",
+      "18efd17ed72a6e92ef8b0a692cf7a2e3", "63a6e0abfb839b43c68c23b2c43c8918",
+      "be15479205bb60f5a17baaa81a6b47ad", "243d21e1d9f9dd2b981292ac7769315a",
+      "21de1cb5269e0e1d08930c519e676bf7", "73065b3e27e9c4a3a6d043712d3d8b25",
+  };
+  static const char* const kDigests32x32[kNumIntraPredictors] = {
+      "c3136bb829088e33401b1affef91f692", "68bbcf93d17366db38bbc7605e07e322",
+      "2786be5fb7c25eeec4d2596c4154c3eb", "25ac7468e691753b8291be859aac7493",
+      "a6805ce21bfd26760e749efc8f590fa3", "5a38fd324b466e8ac43f5e289d38107e",
+      "dd0628fc5cc920b82aa941378fa907c8", "8debadbdb2dec3dc7eb43927e9d36998",
+      "61e1bc223c9e04c64152cc4531b6c099", "900b00ac1f20c0a8d22f8b026c0ee1cc",
+  };
+  static const char* const kDigests32x64[kNumIntraPredictors] = {
+      "5a591b2b83f0a6cce3c57ce164a5f983", "f42167ec516102b83b2c5176df57316b",
+      "58f3772d3df511c8289b340beb178d96", "c24166e7dc252d34ac6f92712956d751",
+      "7dca3acfe2ea09e6292a9ece2078b827", "5c029235fc0820804e40187d2b22a96e",
+      "375572944368afbc04ca97dab7fb3328", "8867235908736fd99c4022e4ed604e6e",
+      "63ec336034d62846b75558c49082870f", "46f35d85eb8499d61bfeac1c49e52531",
+  };
+  static const char* const kDigests64x16[kNumIntraPredictors] = {
+      "67755882209304659a0e6bfc324e16b9", "cd89b272fecb5f23431b3f606f590722",
+      "9bcff7d971a4af0a2d1cac6d66d83482", "d8d6bb55ebeec4f03926908d391e15ba",
+      "0eb5b5ced3e7177a1dd6a1e72e7a7d21", "92b47fe431d9cf66f9e601854f0f3017",
+      "7dc599557eddb2ea480f86fc89c76b30", "4f40175676c164320fe8005440ad9217",
+      "b00eacb24081a041127f136e9e5983ec", "cb0ab76a5e90f2eb75c38b99b9833ff8",
+  };
+  static const char* const kDigests64x32[kNumIntraPredictors] = {
+      "21d873011d1b4ef1daedd9aa8c6938ea", "4866da21db0261f738903d97081cb785",
+      "a722112233a82595a8d001a4078b834d", "24c7a133c6fcb59129c3782ef908a6c1",
+      "490e40505dd255d3a909d8a72c280cbc", "2afe719fb30bf2a664829bb74c8f9e2a",
+      "623adad2ebb8f23e355cd77ace4616cd", "d6092541e9262ad009bef79a5d350a86",
+      "ae86d8fba088683ced8abfd7e1ddf380", "32aa8aa21f2f24333d31f99e12b95c53",
+  };
+  static const char* const kDigests64x64[kNumIntraPredictors] = {
+      "6d88aeb40dfe3ac43c68808ca3c00806", "6a75d88ac291d6a3aaf0eec0ddf2aa65",
+      "30ef52d7dc451affdd587c209f5cb2dd", "e073f7969f392258eaa907cf0636452a",
+      "de10f07016a2343bcd3a9deb29f4361e", "dc35ff273fea4355d2c8351c2ed14e6e",
+      "01b9a545968ac75c3639ddabb837fa0b", "85c98ed9c0ea1523a15281bc9a909b8c",
+      "4c255f7ef7fd46db83f323806d79dca4", "fe2fe6ffb19cb8330e2f2534271d6522",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(IntraPredTest10bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetIntraPredDigests10bpp(tx_size_), num_runs);
+}
+
+TEST_P(IntraPredTest10bpp, FixedInput) {
+  TestSpeed(GetIntraPredDigests10bpp(tx_size_), 1);
+}
+
+TEST_P(IntraPredTest10bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(IntraPredTest10bpp, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using IntraPredTest12bpp = IntraPredTest<12, uint16_t>;
+
+const char* const* GetIntraPredDigests12bpp(TransformSize tx_size) {
+  static const char* const kDigests4x4[kNumIntraPredictors] = {
+      "f7008e0f65bdeed97375ae5e98e3309b", "a34cc5d9d1ef875df4ee2ce010d0a80a",
+      "74f615beeb217ad317ced813851be36a", "b3312e86313805b061c66a08e09de653",
+      "2db47240c95530b39084bdacccf4bb8e", "76bb839cac394b5777c64b6d4b570a27",
+      "a74ee60527be86059e822f7463f49ad5", "b157a40aaa14391c237471ba6d148a50",
+      "d4f7bd2e97e2b23f7a6a059837a10b2a", "8a9bcb30e9aff59b6feef5d1bf546d28",
+  };
+  static const char* const kDigests4x8[kNumIntraPredictors] = {
+      "4c2a59e1d4a58c129c709f05d1a83f4a", "5fbedd99a90a20727195dfbe8f9969ad",
+      "d4645e21ccf5f6d3c4ca7a3d9b0156ba", "98aa17ea5423192c81a04afd2d2669ed",
+      "67dad5b5eefdeb2af1e4d3875b282c6c", "881dcafd6323509fb80cd5bbdf2870c4",
+      "03ece373dfd56bd2fd86ad00ad6f5000", "41b28f2578d2ed7f38e708d57b231948",
+      "9f935505190f52ff4da9556e43f607be", "815700d2abb055bce6902d130e77416d",
+  };
+  static const char* const kDigests4x16[kNumIntraPredictors] = {
+      "bfc47cd4eef143a6ebf517730756a718", "ef07a3af3e353f9dfaebc48c8ac92c82",
+      "ceec5d9d24254efd3c6a00cbf11dd24d", "4e07f512a69cf95608c3c0c3013ed808",
+      "cedb7c900bb6839026bf79d054edb4fc", "48d958a18a019809f12eb2ad2eb358bc",
+      "8f296f4b9fb621a910368609cc2cccdf", "073a6f2ca8a23d6131ff97e2a3b736e1",
+      "f4772cc60b68c4f958c08c0fd8eb8d48", "2f8946cf19abecf0fda3addbfb8f9dcf",
+  };
+  static const char* const kDigests8x4[kNumIntraPredictors] = {
+      "4f245b07a91e6d604da9f22cf277d6f1", "a6dc25d1e24ba9e842c312f67eea211d",
+      "0475204441f44ea95bfd69c6e04eaed8", "313bcf1e2fc762d31ff765d3c18a6f67",
+      "7e9223ece684a1885c2108741052c6c8", "79f1e6f070d9b1d0f1de2ff77bccc0dc",
+      "63adca1101ee4799b1cfa26d88aa0657", "e8b940a5e39ea5313930c903464de843",
+      "42a8e470d3b000f4f57c44c632f0051b", "e8a57663f73da3d4320f8e82a3fecfc2",
+  };
+  static const char* const kDigests8x8[kNumIntraPredictors] = {
+      "7fa3c8bdd9ce04dc4df27863499cf4d4", "83f1312edd9af928a1cef60613730bc3",
+      "ceb35042adc6095a545b490f20e5d81b", "73aa503f329a055ff59a24093e682c41",
+      "14a9a427525ec38d2eb13e698728e911", "9143ddf66234e74acc156565d684fcac",
+      "05182bbe4fd90f3b496033ee5b7c54f9", "d9c6184c23af1f5a903a4a00539b883a",
+      "c4c2d4000ca2defc7a8169215121d9fc", "0b938bc7782b32796bffece28d17bb69",
+  };
+  static const char* const kDigests8x16[kNumIntraPredictors] = {
+      "50197f063138616c37ef09f8bf8a3016", "ef2008f6d9f2176feb17b7d4312022e2",
+      "0d243ffbba0a2e65738d7ee768620c36", "51b52564a2733c2c56ba319db5d8e3b8",
+      "0e2b41482ac1347c3bb6d0e394fe7bec", "edb43c19850452e6b20dfb2c001adb0b",
+      "6cd29f537b5e4180f5aaefd9140b65ef", "6808f618bdff33e0f3d6db60ea487bc1",
+      "0303c17746192b0c52b4d75ea97ca24d", "225d1debd7828fa01bc9a610a443cda9",
+  };
+  static const char* const kDigests8x32[kNumIntraPredictors] = {
+      "dc047c402c6ac4014d621fbd41b460d5", "49eb33c3a112f059e02d6d4b99da8b41",
+      "c906c9105a406ae6c63e69f57ed2fc7c", "2ead452591ddd2455660f96ce79314ab",
+      "437a2a78562752ee8291227f88e0323a", "51834dbdcf1e89667ffbb931bec9006c",
+      "959c1778e11a7c61a5a97176c79ecb6a", "2e51e44dd1953fc6fccc3b1c1ca602ed",
+      "7f94114cddb0ba780cc0c8d00db3f8d2", "b5b3770e6061249a3206915a3f9464e7",
+  };
+  static const char* const kDigests16x4[kNumIntraPredictors] = {
+      "9deb173fa962d9adde8a9ae256708c32", "264624b41e43cfe9378ee9b4fb5028a6",
+      "404919a41bdc7f1a1f9d089223373bb8", "5294ed9fcc16eaf5f9a1f66a2a36ae7c",
+      "a2ed1fa4262bca265dcc62eb1586f0ac", "58494af62f86464dbe471130b2bc4ab0",
+      "fe1f25f7096fc3426cc7964326cc46ad", "cf7f6c8f7257436b9934cecf3b7523e1",
+      "6325036f243abfcd7777754e6a7bdacc", "9dce11a98e18422b04dd9d7be7d420da",
+  };
+  static const char* const kDigests16x8[kNumIntraPredictors] = {
+      "92d5b7d4033dcd8cb729bf8e166e339a", "6cbd9f198828fd3422c9bfaf8c2f1c1d",
+      "2b204014b6dc477f67b36818bcdab1ca", "2ce0b9cf224d4654168c559d7c1424c2",
+      "ec70341b9dd57b379f5283820c9461c7", "3fe1e2a20e44171c90ebca5a45b83460",
+      "0305852b25351ff472a45f45ec1638fa", "565c78271fbe3b25b0eee542095be005",
+      "8bc15e98659cef6236bcb072541bb2ca", "875c87bf4daba7cb436ea2fdb5a427dd",
+  };
+  static const char* const kDigests16x16[kNumIntraPredictors] = {
+      "c9d12bce78d8846f081345906e1315f4", "0b57c8fde6dec15458b1c289245100cb",
+      "1c11978c4e6bbc77767395c63d2f70a8", "e749f26b26b46d8cb7cb13c1c777db94",
+      "40459af05e865e94ff7adcdec1685c15", "f3ae419e99a60dbde3afa24ba6588a36",
+      "fe3912418bca24cee3132de2c193d1fc", "cdc8e3ce27a12f1cbfe01d1adf2eb6bd",
+      "ce354b30ce15a6918172dea55a292b93", "e762d01726d641194982a5fb8c148eb7",
+  };
+  static const char* const kDigests16x32[kNumIntraPredictors] = {
+      "ad8f118b07e053df3887215449633a07", "e8979aa743aef82937d93d87fc9fdb85",
+      "a8afb62cbf602cfcd4b570832afe1d55", "404183cf003764a4f032f0f4810cd42c",
+      "4afcf1bc5589a13b11679571aa953b86", "202df8f5a2d7eb3816de172608115f2b",
+      "ce42bca92d6d7f9df85dbaac72e35064", "61c463c8070b78ca2bdf578044fec440",
+      "3abf6e4d779208e15e3f9a0dfc0254f9", "13df5504084105af7c66a1b013fe44e1",
+  };
+  static const char* const kDigests16x64[kNumIntraPredictors] = {
+      "3ac1f642019493dec1b737d7a3a1b4e5", "cbf69d5d157c9f3355a4757b1d6e3414",
+      "96d00ddc7537bf7f196006591b733b4e", "8cba1b70a0bde29e8ef235cedc5faa7d",
+      "35f9ee300d7fa3c97338e81a6f21dcd4", "aae335442e77c8ebc280f16ea50ba9c7",
+      "a6140fdac2278644328be094d88731db", "2df93621b6ff100f7008432d509f4161",
+      "c77bf5aee39e7ed4a3dd715f816f452a", "02109bd63557d90225c32a8f1338258e",
+  };
+  static const char* const kDigests32x8[kNumIntraPredictors] = {
+      "155688dec409ff50f2333c14a6367247", "cf935e78abafa6ff7258c5af229f55b6",
+      "b4bf83a28ba319c597151a041ff838c3", "fe97f3e6cd5fe6c5979670c11d940dda",
+      "b898c9a989e1e72461a6f47e913d5383", "bb73baa6476ce90118e83e2fd08f2299",
+      "c93be6d8ec318bd805899466821bb779", "ab366991ef842e9d417d52241f6966e6",
+      "9e7e4c96a271e9e40771eac39c21f661", "9459f2e6d1291b8b8a2fe0635ce1a33d",
+  };
+  static const char* const kDigests32x16[kNumIntraPredictors] = {
+      "48374c1241409e26d81e5106c73da420", "97c918bdba2ece52156dbc776b9b70d4",
+      "a44ce9c03f6622a3e93bfe3b928eb6f1", "2384ad95e3e7302f20857121e187aa48",
+      "47e72c6dc0087b6fd99e91cff854c269", "142dc3cbb05b82a496780f7fc3d66ccc",
+      "4a39fb768efcd4f30d6eae816e6a68c4", "d0c31f9d52d984a0335557eafe2b47fa",
+      "81b3af5c7893729b837e4d304917f7cd", "941cbcd411887dc7fa3a5c7395690d1a",
+  };
+  static const char* const kDigests32x32[kNumIntraPredictors] = {
+      "00892ee43a1bbb11347c1f44fb94b1a2", "d66397ba868e62cec99daf5ea73bebd0",
+      "65fe746e79ac1e779caae8abcc15eb6b", "8e308fe96b9845112d79c54f9d7981a0",
+      "47bc8847a7c9aed3417cd5250ba57875", "1a4008b7f0f61a3c73a2ee1d1452b414",
+      "24d25ef488bb457a5a4c4892e47a363d", "6d9d964f5317ab32a8edf57c23775238",
+      "544fc36c1a35c588359ae492cb5bc143", "ac170d94dbd944e9723de9c18bace1a3",
+  };
+  static const char* const kDigests32x64[kNumIntraPredictors] = {
+      "7d0bd7dea26226741dbca9a97f27fa74", "a8bdc852ef704dd4975c61893e8fbc3f",
+      "f29d6d03c143ddf96fef04c19f2c8333", "ad9cfc395a5c5644a21d958c7274ac14",
+      "45c27c5cca9a91b6ae8379feb0881c9f", "8a0b78df1e001b85c874d686eac4aa1b",
+      "ce9fa75fac54a3f6c0cc3f2083b938f1", "c0dca10d88762c954af18dc9e3791a39",
+      "61df229eddfccab913b8fda4bb02f9ac", "4f4df6bc8d50a5600b573f0e44d70e66",
+  };
+  static const char* const kDigests64x16[kNumIntraPredictors] = {
+      "e99d072de858094c98b01bd4a6772634", "525da4b187acd81b1ff1116b60461141",
+      "1348f249690d9eefe09d9ad7ead2c801", "a5e2f9fb685d5f4a048e9a96affd25a4",
+      "873bfa9dc24693f19721f7c8d527f7d3", "0acfc6507bd3468e9679efc127d6e4b9",
+      "57d03f8d079c7264854e22ac1157cfae", "6c2c4036f70c7d957a9399b5436c0774",
+      "42b8e4a97b7f8416c72a5148c031c0b1", "a38a2c5f79993dfae8530e9e25800893",
+  };
+  static const char* const kDigests64x32[kNumIntraPredictors] = {
+      "68bd283cfd1a125f6b2ee47cee874d36", "b4581311a0a73d95dfac7f8f44591032",
+      "5ecc7fdc52d2f575ad4f2d0e9e6b1e11", "db9d82921fd88b24fdff6f849f2f9c87",
+      "804179f05c032908a5e36077bb87c994", "fc5fd041a8ee779015394d0c066ee43c",
+      "68f5579ccadfe9a1baafb158334a3db2", "fe237e45e215ab06d79046da9ad71e84",
+      "9a8a938a6824551bf7d21b8fd1d70ea1", "eb7332f2017cd96882c76e7136aeaf53",
+  };
+  static const char* const kDigests64x64[kNumIntraPredictors] = {
+      "d9a906c0e692b22e1b4414e71a704b7e", "12ac11889ae5f55b7781454efd706a6a",
+      "3f1ef5f473a49eba743f17a3324adf9d", "a6baa0d4bfb2269a94c7a38f86a4bccf",
+      "47d4cadd56f70c11ff8f3e5d8df81161", "de997744cf24c16c5ac2a36b02b351cc",
+      "23781211ae178ddeb6c4bb97a6bd7d83", "a79d2e28340ca34b9e37daabbf030f63",
+      "0372bd3ddfc258750a6ac106b70587f4", "228ef625d9460cbf6fa253a16a730976",
+  };
+
+  switch (tx_size) {
+    case kTransformSize4x4:
+      return kDigests4x4;
+    case kTransformSize4x8:
+      return kDigests4x8;
+    case kTransformSize4x16:
+      return kDigests4x16;
+    case kTransformSize8x4:
+      return kDigests8x4;
+    case kTransformSize8x8:
+      return kDigests8x8;
+    case kTransformSize8x16:
+      return kDigests8x16;
+    case kTransformSize8x32:
+      return kDigests8x32;
+    case kTransformSize16x4:
+      return kDigests16x4;
+    case kTransformSize16x8:
+      return kDigests16x8;
+    case kTransformSize16x16:
+      return kDigests16x16;
+    case kTransformSize16x32:
+      return kDigests16x32;
+    case kTransformSize16x64:
+      return kDigests16x64;
+    case kTransformSize32x8:
+      return kDigests32x8;
+    case kTransformSize32x16:
+      return kDigests32x16;
+    case kTransformSize32x32:
+      return kDigests32x32;
+    case kTransformSize32x64:
+      return kDigests32x64;
+    case kTransformSize64x16:
+      return kDigests64x16;
+    case kTransformSize64x32:
+      return kDigests64x32;
+    case kTransformSize64x64:
+      return kDigests64x64;
+    default:
+      ADD_FAILURE() << "Unknown transform size: " << tx_size;
+      return nullptr;
+  }
+}
+
+TEST_P(IntraPredTest12bpp, DISABLED_Speed) {
+  const auto num_runs =
+      static_cast<int>(2.0e9 / (block_width_ * block_height_));
+  TestSpeed(GetIntraPredDigests12bpp(tx_size_), num_runs);
+}
+
+TEST_P(IntraPredTest12bpp, FixedInput) {
+  TestSpeed(GetIntraPredDigests12bpp(tx_size_), 1);
+}
+
+TEST_P(IntraPredTest12bpp, Overflow) { TestSaturatedValues(); }
+TEST_P(IntraPredTest12bpp, Random) { TestRandomValues(); }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+constexpr TransformSize kTransformSizes[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
+    kTransformSize32x8,  kTransformSize32x16, kTransformSize32x32,
+    kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
+    kTransformSize64x64};
+
+INSTANTIATE_TEST_SUITE_P(C, IntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, IntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, IntraPredTest8bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, IntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, IntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_SSE4_1
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, IntraPredTest10bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, IntraPredTest12bpp,
+                         testing::ValuesIn(kTransformSizes));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const TransformSize tx_size) {
+  return os << ToString(tx_size);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/inverse_transform_test.cc b/src/dsp/inverse_transform_test.cc
new file mode 100644
index 0000000..081dcc1
--- /dev/null
+++ b/src/dsp/inverse_transform_test.cc
@@ -0,0 +1,558 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/inverse_transform.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <ostream>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/bit_mask_set.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMaxBlockSize = 64;
+constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
+
+const char* const kTransform1dSizeNames[kNumTransform1dSizes] = {
+    "kTransform1dSize4", "kTransform1dSize8", "kTransform1dSize16",
+    "kTransform1dSize32", "kTransform1dSize64"};
+
+constexpr Transform1dSize kRowTransform1dSizes[] = {
+    kTransform1dSize4,  kTransform1dSize4,  kTransform1dSize4,
+    kTransform1dSize8,  kTransform1dSize8,  kTransform1dSize8,
+    kTransform1dSize8,  kTransform1dSize16, kTransform1dSize16,
+    kTransform1dSize16, kTransform1dSize16, kTransform1dSize16,
+    kTransform1dSize32, kTransform1dSize32, kTransform1dSize32,
+    kTransform1dSize32, kTransform1dSize64, kTransform1dSize64,
+    kTransform1dSize64};
+
+constexpr Transform1dSize kColTransform1dSizes[] = {
+    kTransform1dSize4,  kTransform1dSize8,  kTransform1dSize16,
+    kTransform1dSize4,  kTransform1dSize8,  kTransform1dSize16,
+    kTransform1dSize32, kTransform1dSize4,  kTransform1dSize8,
+    kTransform1dSize16, kTransform1dSize32, kTransform1dSize64,
+    kTransform1dSize8,  kTransform1dSize16, kTransform1dSize32,
+    kTransform1dSize64, kTransform1dSize16, kTransform1dSize32,
+    kTransform1dSize64};
+
+template <int bitdepth, typename SrcPixel, typename DstPixel>
+class InverseTransformTestBase : public testing::TestWithParam<TransformSize>,
+                                 public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  InverseTransformTestBase() {
+    switch (tx_size_) {
+      case kNumTransformSizes:
+        EXPECT_NE(tx_size_, kNumTransformSizes);
+        break;
+      default:
+        block_width_ = kTransformWidth[tx_size_];
+        block_height_ = kTransformHeight[tx_size_];
+        break;
+    }
+  }
+
+  InverseTransformTestBase(const InverseTransformTestBase&) = delete;
+  InverseTransformTestBase& operator=(const InverseTransformTestBase&) = delete;
+  ~InverseTransformTestBase() override = default;
+
+ protected:
+  struct InverseTransformMem {
+    void Reset(libvpx_test::ACMRandom* rnd, int width, int height) {
+      ASSERT_NE(rnd, nullptr);
+      // Limit the size of the residual values to bitdepth + sign in order
+      // to prevent outranging in the transforms.
+      const int num_bits = bitdepth + 1;
+      const int sign_shift = (bitdepth == 8 ? 16 : 32) - num_bits;
+      const int mask = (1 << num_bits) - 1;
+      // Fill residual with random data.  For widths == 64, only fill the upper
+      // left 32 x min(block_height_, 32).
+      memset(ref_src, 0, sizeof(ref_src));
+      SrcPixel* r = ref_src;
+      const int stride = width;
+      for (int y = 0; y < std::min(height, 32); ++y) {
+        for (int x = 0; x < std::min(width, 32); ++x) {
+          r[x] = rnd->Rand16() & mask;
+          // The msb of num_bits is the sign bit, so force each 16 bit value to
+          // the correct sign.
+          r[x] = (r[x] << sign_shift) >> sign_shift;
+        }
+        r += stride;
+      }
+
+      // Set frame data to random values.
+      for (int y = 0; y < kMaxBlockSize; ++y) {
+        for (int x = 0; x < kMaxBlockSize; ++x) {
+          const int mask = (1 << bitdepth) - 1;
+          cur_frame[y * kMaxBlockSize + x] = base_frame[y * kMaxBlockSize + x] =
+              rnd->Rand16() & mask;
+        }
+      }
+    }
+
+    // Set ref_src to |pixel|.
+    void Set(const SrcPixel pixel) {
+      for (auto& r : ref_src) r = pixel;
+    }
+
+    alignas(kMaxAlignment) DstPixel base_frame[kTotalPixels];
+    alignas(kMaxAlignment) DstPixel cur_frame[kTotalPixels];
+
+    alignas(kMaxAlignment) SrcPixel base_residual[kTotalPixels];
+    alignas(kMaxAlignment) SrcPixel cur_residual[kTotalPixels];
+
+    alignas(kMaxAlignment) SrcPixel ref_src[kTotalPixels];
+  };
+
+  void SetUp() override { test_utils::ResetDspTable(bitdepth); }
+
+  const TransformSize tx_size_ = GetParam();
+  int block_width_;
+  int block_height_;
+  InverseTransformMem inverse_transform_mem_;
+};
+
+//------------------------------------------------------------------------------
+// InverseTransformTest
+
+template <int bitdepth, typename Pixel, typename DstPixel>
+class InverseTransformTest
+    : public InverseTransformTestBase<bitdepth, Pixel, DstPixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  InverseTransformTest() = default;
+  InverseTransformTest(const InverseTransformTest&) = delete;
+  InverseTransformTest& operator=(const InverseTransformTest&) = delete;
+  ~InverseTransformTest() override = default;
+
+ protected:
+  using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::tx_size_;
+  using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::block_width_;
+  using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::block_height_;
+  using InverseTransformTestBase<bitdepth, Pixel,
+                                 DstPixel>::inverse_transform_mem_;
+
+  void SetUp() override {
+    InverseTransformTestBase<bitdepth, Pixel, DstPixel>::SetUp();
+    InverseTransformInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+
+    tx_size_1d_row_ = kRowTransform1dSizes[tx_size_];
+    tx_size_1d_column_ = kColTransform1dSizes[tx_size_];
+
+    memcpy(base_inverse_transforms_, dsp->inverse_transforms,
+           sizeof(base_inverse_transforms_));
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      memset(base_inverse_transforms_, 0, sizeof(base_inverse_transforms_));
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        InverseTransformInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      InverseTransformInit_NEON();
+      InverseTransformInit10bpp_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    memcpy(cur_inverse_transforms_, dsp->inverse_transforms,
+           sizeof(cur_inverse_transforms_));
+
+    for (int i = 0; i < kNumTransform1ds; ++i) {
+      // skip functions that haven't been specialized for this particular
+      // architecture.
+      if (cur_inverse_transforms_[i][tx_size_1d_row_][kRow] ==
+          base_inverse_transforms_[i][tx_size_1d_row_][kRow]) {
+        cur_inverse_transforms_[i][tx_size_1d_row_][kRow] = nullptr;
+      }
+      if (cur_inverse_transforms_[i][tx_size_1d_column_][kColumn] ==
+          base_inverse_transforms_[i][tx_size_1d_column_][kColumn]) {
+        cur_inverse_transforms_[i][tx_size_1d_column_][kColumn] = nullptr;
+      }
+    }
+
+    base_frame_buffer_.Reset(kMaxBlockSize, kMaxBlockSize,
+                             inverse_transform_mem_.base_frame);
+
+    cur_frame_buffer_.Reset(kMaxBlockSize, kMaxBlockSize,
+                            inverse_transform_mem_.cur_frame);
+  }
+
+  // These tests modify inverse_transform_mem_.
+  void TestRandomValues(int num_tests);
+  void TestDcOnlyRandomValue(int num_tests);
+
+  Array2DView<DstPixel> base_frame_buffer_;
+  Array2DView<DstPixel> cur_frame_buffer_;
+
+  Transform1dSize tx_size_1d_row_ = kTransform1dSize4;
+  Transform1dSize tx_size_1d_column_ = kTransform1dSize4;
+
+  InverseTransformAddFuncs base_inverse_transforms_;
+  InverseTransformAddFuncs cur_inverse_transforms_;
+};
+
+constexpr TransformType kLibgav1TxType[kNumTransformTypes] = {
+    kTransformTypeDctDct,           kTransformTypeAdstDct,
+    kTransformTypeDctAdst,          kTransformTypeAdstAdst,
+    kTransformTypeFlipadstDct,      kTransformTypeDctFlipadst,
+    kTransformTypeFlipadstFlipadst, kTransformTypeAdstFlipadst,
+    kTransformTypeFlipadstAdst,     kTransformTypeIdentityIdentity,
+    kTransformTypeIdentityDct,      kTransformTypeDctIdentity,
+    kTransformTypeIdentityAdst,     kTransformTypeAdstIdentity,
+    kTransformTypeIdentityFlipadst, kTransformTypeFlipadstIdentity};
+
+// Maps TransformType to dsp::Transform1d for the row transforms.
+constexpr Transform1d kRowTransform[kNumTransformTypes] = {
+    kTransform1dDct,      kTransform1dAdst,     kTransform1dDct,
+    kTransform1dAdst,     kTransform1dAdst,     kTransform1dDct,
+    kTransform1dAdst,     kTransform1dAdst,     kTransform1dAdst,
+    kTransform1dIdentity, kTransform1dIdentity, kTransform1dDct,
+    kTransform1dIdentity, kTransform1dAdst,     kTransform1dIdentity,
+    kTransform1dAdst};
+
+// Maps TransformType to dsp::Transform1d for the column transforms.
+constexpr Transform1d kColumnTransform[kNumTransformTypes] = {
+    kTransform1dDct,      kTransform1dDct,      kTransform1dAdst,
+    kTransform1dAdst,     kTransform1dDct,      kTransform1dAdst,
+    kTransform1dAdst,     kTransform1dAdst,     kTransform1dAdst,
+    kTransform1dIdentity, kTransform1dDct,      kTransform1dIdentity,
+    kTransform1dAdst,     kTransform1dIdentity, kTransform1dAdst,
+    kTransform1dIdentity};
+
+// Mask indicating whether the transform sets contain a particular transform
+// type. If |tx_type| is present in |tx_set|, then the |tx_type|th LSB is set.
+constexpr BitMaskSet kTransformTypeInSetMask[kNumTransformSets] = {
+    BitMaskSet(0x1),    BitMaskSet(0xE0F), BitMaskSet(0x20F),
+    BitMaskSet(0xFFFF), BitMaskSet(0xFFF), BitMaskSet(0x201)};
+
+bool IsTxSizeTypeValid(TransformSize tx_size, TransformType tx_type) {
+  const TransformSize tx_size_square_max = kTransformSizeSquareMax[tx_size];
+  TransformSet tx_set;
+  if (tx_size_square_max > kTransformSize32x32) {
+    tx_set = kTransformSetDctOnly;
+  } else if (tx_size_square_max == kTransformSize32x32) {
+    tx_set = kTransformSetInter3;
+  } else if (tx_size_square_max == kTransformSize16x16) {
+    tx_set = kTransformSetInter2;
+  } else {
+    tx_set = kTransformSetInter1;
+  }
+  return kTransformTypeInSetMask[tx_set].Contains(tx_type);
+}
+
+template <int bitdepth, typename Pixel, typename DstPixel>
+void InverseTransformTest<bitdepth, Pixel, DstPixel>::TestRandomValues(
+    int num_tests) {
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+
+  for (int tx_type_idx = -1; tx_type_idx < kNumTransformTypes; ++tx_type_idx) {
+    const TransformType tx_type = (tx_type_idx == -1)
+                                      ? kTransformTypeDctDct
+                                      : kLibgav1TxType[tx_type_idx];
+    const Transform1d row_transform =
+        (tx_type_idx == -1) ? kTransform1dWht : kRowTransform[tx_type];
+    const Transform1d column_transform =
+        (tx_type_idx == -1) ? kTransform1dWht : kColumnTransform[tx_type];
+
+    // Skip the 'C' test case as this is used as the reference.
+    if (base_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
+            nullptr ||
+        cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
+            nullptr ||
+        base_inverse_transforms_[column_transform][tx_size_1d_column_]
+                                [kColumn] == nullptr ||
+        cur_inverse_transforms_[column_transform][tx_size_1d_column_]
+                               [kColumn] == nullptr) {
+      continue;
+    }
+
+    // Only test valid tx_size for given tx_type.  See 5.11.40.
+    if (!IsTxSizeTypeValid(tx_size_, tx_type)) continue;
+
+    absl::Duration base_elapsed_time[2];
+    absl::Duration cur_elapsed_time[2];
+
+    for (int n = 0; n < num_tests; ++n) {
+      const int tx_height = std::min(block_height_, 32);
+      const int start_x = 0;
+      const int start_y = 0;
+
+      inverse_transform_mem_.Reset(&rnd, block_width_, block_height_);
+      memcpy(inverse_transform_mem_.base_residual,
+             inverse_transform_mem_.ref_src,
+             sizeof(inverse_transform_mem_.ref_src));
+      memcpy(inverse_transform_mem_.cur_residual,
+             inverse_transform_mem_.ref_src,
+             sizeof(inverse_transform_mem_.ref_src));
+
+      const absl::Time base_row_start = absl::Now();
+      base_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
+          start_x, start_y, &base_frame_buffer_);
+      base_elapsed_time[kRow] += absl::Now() - base_row_start;
+
+      const absl::Time cur_row_start = absl::Now();
+      cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.cur_residual,
+          start_x, start_y, &cur_frame_buffer_);
+      cur_elapsed_time[kRow] += absl::Now() - cur_row_start;
+
+      const absl::Time base_column_start = absl::Now();
+      base_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
+          start_x, start_y, &base_frame_buffer_);
+      base_elapsed_time[kColumn] += absl::Now() - base_column_start;
+
+      const absl::Time cur_column_start = absl::Now();
+      cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.cur_residual,
+          start_x, start_y, &cur_frame_buffer_);
+      cur_elapsed_time[kColumn] += absl::Now() - cur_column_start;
+
+      if (!test_utils::CompareBlocks(inverse_transform_mem_.base_frame,
+                                     inverse_transform_mem_.cur_frame,
+                                     block_width_, block_height_, kMaxBlockSize,
+                                     kMaxBlockSize, false)) {
+        ADD_FAILURE() << "Result from optimized version of "
+                      << ToString(
+                             static_cast<Transform1dSize>(tx_size_1d_column_))
+                      << " differs from reference in iteration #" << n
+                      << " tx_type_idx:" << tx_type_idx;
+        break;
+      }
+    }
+
+    if (num_tests > 1) {
+      const auto base_row_elapsed_time_us =
+          static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time[kRow]));
+      const auto cur_row_elapsed_time_us =
+          static_cast<int>(absl::ToInt64Microseconds(cur_elapsed_time[kRow]));
+      printf("TxType %30s[%19s]:: base_row: %5d us  cur_row: %5d us  %2.2fx \n",
+             (tx_type_idx == -1) ? ToString(row_transform) : ToString(tx_type),
+             kTransform1dSizeNames[tx_size_1d_row_], base_row_elapsed_time_us,
+             cur_row_elapsed_time_us,
+             static_cast<float>(base_row_elapsed_time_us) /
+                 static_cast<float>(cur_row_elapsed_time_us));
+      const auto base_column_elapsed_time_us = static_cast<int>(
+          absl::ToInt64Microseconds(base_elapsed_time[kColumn]));
+      const auto cur_column_elapsed_time_us = static_cast<int>(
+          absl::ToInt64Microseconds(cur_elapsed_time[kColumn]));
+      printf(
+          "TxType %30s[%19s]:: base_col: %5d us  cur_col: %5d us  %2.2fx \n",
+          (tx_type_idx == -1) ? ToString(column_transform) : ToString(tx_type),
+          kTransform1dSizeNames[tx_size_1d_column_],
+          base_column_elapsed_time_us, cur_column_elapsed_time_us,
+          static_cast<float>(base_column_elapsed_time_us) /
+              static_cast<float>(cur_column_elapsed_time_us));
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel, typename DstPixel>
+void InverseTransformTest<bitdepth, Pixel, DstPixel>::TestDcOnlyRandomValue(
+    int num_tests) {
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+
+  for (int tx_type_idx = 0; tx_type_idx < kNumTransformTypes; ++tx_type_idx) {
+    const TransformType tx_type = kLibgav1TxType[tx_type_idx];
+    const Transform1d row_transform = kRowTransform[tx_type];
+    const Transform1d column_transform = kColumnTransform[tx_type];
+
+    if (cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
+            nullptr ||
+        cur_inverse_transforms_[column_transform][tx_size_1d_column_]
+                               [kColumn] == nullptr) {
+      continue;
+    }
+
+    // Only test valid tx_size for given tx_type.  See 5.11.40.
+    if (IsTxSizeTypeValid(tx_size_, tx_type) == 0) continue;
+
+    absl::Duration base_elapsed_time[2];
+    absl::Duration cur_elapsed_time[2];
+
+    for (int n = 0; n < num_tests; ++n) {
+      const int tx_height = std::min(block_height_, 32);
+      const int start_x = 0;
+      const int start_y = 0;
+
+      // Using width == 1 and height == 1 will reset only the dc value.
+      inverse_transform_mem_.Reset(&rnd, 1, 1);
+      memcpy(inverse_transform_mem_.base_residual,
+             inverse_transform_mem_.ref_src,
+             sizeof(inverse_transform_mem_.ref_src));
+      memcpy(inverse_transform_mem_.cur_residual,
+             inverse_transform_mem_.ref_src,
+             sizeof(inverse_transform_mem_.ref_src));
+
+      // For this test, the "base" contains the output when the
+      // tx_height is set to the max for the given block size.  The
+      // "cur" contains the output when the passed in tx_height is 1.
+      // Compare the outputs for match.
+      const absl::Time base_row_start = absl::Now();
+      cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
+          start_x, start_y, &base_frame_buffer_);
+      base_elapsed_time[kRow] += absl::Now() - base_row_start;
+
+      const absl::Time cur_row_start = absl::Now();
+      cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
+          tx_type, tx_size_, /*adjusted_tx_height=*/1,
+          inverse_transform_mem_.cur_residual, start_x, start_y,
+          &cur_frame_buffer_);
+      cur_elapsed_time[kRow] += absl::Now() - cur_row_start;
+
+      const absl::Time base_column_start = absl::Now();
+      cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
+          tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
+          start_x, start_y, &base_frame_buffer_);
+      base_elapsed_time[kColumn] += absl::Now() - base_column_start;
+
+      const absl::Time cur_column_start = absl::Now();
+      cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
+          tx_type, tx_size_, /*adjusted_tx_height=*/1,
+          inverse_transform_mem_.cur_residual, start_x, start_y,
+          &cur_frame_buffer_);
+      cur_elapsed_time[kColumn] += absl::Now() - cur_column_start;
+
+      if (!test_utils::CompareBlocks(inverse_transform_mem_.base_frame,
+                                     inverse_transform_mem_.cur_frame,
+                                     block_width_, block_height_, kMaxBlockSize,
+                                     kMaxBlockSize, false)) {
+        ADD_FAILURE() << "Result from dc only version of "
+                      << ToString(
+                             static_cast<Transform1dSize>(tx_size_1d_column_))
+                      << " differs from reference in iteration #" << n
+                      << "tx_type_idx:" << tx_type_idx;
+        break;
+      }
+    }
+
+    if (num_tests > 1) {
+      const auto base_row_elapsed_time_us =
+          static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time[kRow]));
+      const auto cur_row_elapsed_time_us =
+          static_cast<int>(absl::ToInt64Microseconds(cur_elapsed_time[kRow]));
+      printf("TxType %30s[%19s]:: base_row: %5d us  cur_row: %5d us  %2.2fx \n",
+             ToString(tx_type), kTransform1dSizeNames[tx_size_1d_row_],
+             base_row_elapsed_time_us, cur_row_elapsed_time_us,
+             static_cast<float>(base_row_elapsed_time_us) /
+                 static_cast<float>(cur_row_elapsed_time_us));
+      const auto base_column_elapsed_time_us = static_cast<int>(
+          absl::ToInt64Microseconds(base_elapsed_time[kColumn]));
+      const auto cur_column_elapsed_time_us = static_cast<int>(
+          absl::ToInt64Microseconds(cur_elapsed_time[kColumn]));
+      printf("TxType %30s[%19s]:: base_col: %5d us  cur_col: %5d us  %2.2fx \n",
+             ToString(tx_type), kTransform1dSizeNames[tx_size_1d_column_],
+             base_column_elapsed_time_us, cur_column_elapsed_time_us,
+             static_cast<float>(base_column_elapsed_time_us) /
+                 static_cast<float>(cur_column_elapsed_time_us));
+    }
+  }
+}
+
+using InverseTransformTest8bpp = InverseTransformTest<8, int16_t, uint8_t>;
+
+TEST_P(InverseTransformTest8bpp, Random) { TestRandomValues(1); }
+
+TEST_P(InverseTransformTest8bpp, DISABLED_Speed) { TestRandomValues(10000); }
+
+TEST_P(InverseTransformTest8bpp, DcRandom) { TestDcOnlyRandomValue(1); }
+
+constexpr TransformSize kTransformSizesAll[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
+    kTransformSize32x8,  kTransformSize32x16, kTransformSize32x32,
+    kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
+    kTransformSize64x64};
+
+INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest8bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, InverseTransformTest8bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, InverseTransformTest8bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using InverseTransformTest10bpp = InverseTransformTest<10, int32_t, uint16_t>;
+
+TEST_P(InverseTransformTest10bpp, Random) { TestRandomValues(1); }
+
+TEST_P(InverseTransformTest10bpp, DISABLED_Speed) { TestRandomValues(10000); }
+
+TEST_P(InverseTransformTest10bpp, DcRandom) { TestDcOnlyRandomValue(1); }
+
+INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest10bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, InverseTransformTest10bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using InverseTransformTest12bpp = InverseTransformTest<12, int32_t, uint16_t>;
+
+TEST_P(InverseTransformTest12bpp, Random) { TestRandomValues(1); }
+
+TEST_P(InverseTransformTest12bpp, DISABLED_Speed) { TestRandomValues(12000); }
+
+TEST_P(InverseTransformTest12bpp, DcRandom) { TestDcOnlyRandomValue(1); }
+
+INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest12bpp,
+                         testing::ValuesIn(kTransformSizesAll));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+
+static std::ostream& operator<<(std::ostream& os, const TransformSize param) {
+  return os << ToString(param);
+}
+
+}  // namespace libgav1
diff --git a/src/dsp/loop_filter_test.cc b/src/dsp/loop_filter_test.cc
new file mode 100644
index 0000000..63ed530
--- /dev/null
+++ b/src/dsp/loop_filter_test.cc
@@ -0,0 +1,410 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/loop_filter.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <ostream>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/third_party/libvpx/md5_helper.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// Horizontal and Vertical need 32x32: 8  pixels preceding filtered section
+//                                     16 pixels within filtered section
+//                                     8  pixels following filtered section
+constexpr int kNumPixels = 1024;
+constexpr int kBlockStride = 32;
+
+constexpr int kNumTests = 50000;
+constexpr int kNumSpeedTests = 500000;
+
+template <typename Pixel>
+void InitInput(Pixel* dst, const int stride, const int bitdepth,
+               libvpx_test::ACMRandom& rnd, const uint8_t inner_thresh,
+               const bool transpose) {
+  const int max_pixel = (1 << bitdepth) - 1;
+  const int pixel_range = max_pixel + 1;
+  Pixel tmp[kNumPixels];
+  auto clip_pixel = [max_pixel](int val) {
+    return static_cast<Pixel>(std::max(std::min(val, max_pixel), 0));
+  };
+
+  for (int i = 0; i < kNumPixels;) {
+    const uint8_t val = rnd.Rand8();
+    if (val & 0x80) {  // 50% chance to choose a new value.
+      tmp[i++] = rnd(pixel_range);
+    } else {  // 50% chance to repeat previous value in row X times.
+      int j = 0;
+      while (j++ < ((val & 0x1f) + 1) && i < kNumPixels) {
+        if (i < 1) {
+          tmp[i] = rnd(pixel_range);
+        } else if (val & 0x20) {  // Increment by a value within the limit.
+          tmp[i] = clip_pixel(tmp[i - 1] + (inner_thresh - 1));
+        } else {  // Decrement by a value within the limit.
+          tmp[i] = clip_pixel(tmp[i - 1] - (inner_thresh - 1));
+        }
+        ++i;
+      }
+    }
+  }
+
+  for (int i = 0; i < kNumPixels;) {
+    const uint8_t val = rnd.Rand8();
+    if (val & 0x80) {
+      ++i;
+    } else {  // 50% chance to repeat previous value in column X times.
+      int j = 0;
+      while (j++ < ((val & 0x1f) + 1) && i < kNumPixels) {
+        if (i < 1) {
+          tmp[i] = rnd(pixel_range);
+        } else if (val & 0x20) {  // Increment by a value within the limit.
+          tmp[(i % 32) * 32 + i / 32] = clip_pixel(
+              tmp[((i - 1) % 32) * 32 + (i - 1) / 32] + (inner_thresh - 1));
+        } else {  // Decrement by a value within the inner_thresh.
+          tmp[(i % 32) * 32 + i / 32] = clip_pixel(
+              tmp[((i - 1) % 32) * 32 + (i - 1) / 32] - (inner_thresh - 1));
+        }
+        ++i;
+      }
+    }
+  }
+
+  for (int i = 0; i < kNumPixels; ++i) {
+    const int offset = transpose ? stride * (i % stride) + i / stride : i;
+    dst[i] = tmp[offset];
+  }
+}
+
+template <int bitdepth, typename Pixel>
+class LoopFilterTest : public testing::TestWithParam<LoopFilterSize> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  LoopFilterTest() = default;
+  LoopFilterTest(const LoopFilterTest&) = delete;
+  LoopFilterTest& operator=(const LoopFilterTest&) = delete;
+  ~LoopFilterTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    LoopFilterInit_C();
+
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    memcpy(base_loop_filters_, dsp->loop_filters[size_],
+           sizeof(base_loop_filters_));
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      memset(base_loop_filters_, 0, sizeof(base_loop_filters_));
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        LoopFilterInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      LoopFilterInit_NEON();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      LoopFilterInit10bpp_NEON();
+#endif
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+
+    memcpy(cur_loop_filters_, dsp->loop_filters[size_],
+           sizeof(cur_loop_filters_));
+
+    for (int i = 0; i < kNumLoopFilterTypes; ++i) {
+      // skip functions that haven't been specialized for this particular
+      // architecture.
+      if (cur_loop_filters_[i] == base_loop_filters_[i]) {
+        cur_loop_filters_[i] = nullptr;
+      }
+    }
+  }
+
+  // Check |digests| if non-NULL otherwise print the filter timing.
+  void TestRandomValues(const char* const digests[kNumLoopFilterTypes],
+                        int num_runs) const;
+  void TestSaturatedValues() const;
+
+  const LoopFilterSize size_ = GetParam();
+  LoopFilterFunc base_loop_filters_[kNumLoopFilterTypes];
+  LoopFilterFunc cur_loop_filters_[kNumLoopFilterTypes];
+};
+
+template <int bitdepth, typename Pixel>
+void LoopFilterTest<bitdepth, Pixel>::TestRandomValues(
+    const char* const digests[kNumLoopFilterTypes], const int num_runs) const {
+  for (int i = 0; i < kNumLoopFilterTypes; ++i) {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    if (cur_loop_filters_[i] == nullptr) continue;
+
+    libvpx_test::MD5 md5_digest;
+    absl::Duration elapsed_time;
+    for (int n = 0; n < num_runs; ++n) {
+      Pixel dst[kNumPixels];
+      const auto outer_thresh = static_cast<uint8_t>(
+          rnd(3 * kMaxLoopFilterValue - 2) + 7);  // [7, 193].
+      const auto inner_thresh =
+          static_cast<uint8_t>(rnd(kMaxLoopFilterValue) + 1);  // [1, 63].
+      const auto hev_thresh =
+          static_cast<uint8_t>(rnd(kMaxLoopFilterValue + 1) >> 4);  // [0, 3].
+      InitInput(dst, kBlockStride, bitdepth, rnd, inner_thresh, (n & 1) == 0);
+
+      const absl::Time start = absl::Now();
+      cur_loop_filters_[i](dst + 8 + kBlockStride * 8, kBlockStride,
+                           outer_thresh, inner_thresh, hev_thresh);
+      elapsed_time += absl::Now() - start;
+
+      md5_digest.Add(reinterpret_cast<const uint8_t*>(dst), sizeof(dst));
+    }
+    if (digests == nullptr) {
+      const auto elapsed_time_us =
+          static_cast<int>(absl::ToInt64Microseconds(elapsed_time));
+      printf("Mode %s[%25s]: %5d us\n",
+             ToString(static_cast<LoopFilterSize>(size_)),
+             ToString(static_cast<LoopFilterType>(i)), elapsed_time_us);
+    } else {
+      const std::string digest = md5_digest.Get();
+      printf("Mode %s[%25s]: MD5: %s\n",
+             ToString(static_cast<LoopFilterSize>(size_)),
+             ToString(static_cast<LoopFilterType>(i)), digest.c_str());
+      EXPECT_STREQ(digests[i], digest.c_str());
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void LoopFilterTest<bitdepth, Pixel>::TestSaturatedValues() const {
+  Pixel dst[kNumPixels], ref[kNumPixels];
+  const auto value = static_cast<Pixel>((1 << bitdepth) - 1);
+  for (auto& r : dst) r = value;
+  memcpy(ref, dst, sizeof(dst));
+
+  for (int i = 0; i < kNumLoopFilterTypes; ++i) {
+    if (cur_loop_filters_[i] == nullptr) return;
+    const int outer_thresh = 24;
+    const int inner_thresh = 8;
+    const int hev_thresh = 0;
+    cur_loop_filters_[i](dst + 8 + kBlockStride * 8, kBlockStride, outer_thresh,
+                         inner_thresh, hev_thresh);
+    ASSERT_TRUE(test_utils::CompareBlocks(ref, dst, kBlockStride, kBlockStride,
+                                          kBlockStride, kBlockStride, true))
+        << ToString(static_cast<LoopFilterType>(i))
+        << " output doesn't match reference";
+  }
+}
+
+//------------------------------------------------------------------------------
+
+using LoopFilterTest8bpp = LoopFilterTest<8, uint8_t>;
+
+const char* const* GetDigests8bpp(LoopFilterSize size) {
+  static const char* const kDigestsSize4[kNumLoopFilterTypes] = {
+      "6ba725d697d6209cb36dd199b8ffb47a",
+      "7dbb20e456ed0501fb4e7954f49f5e18",
+  };
+  static const char* const kDigestsSize6[kNumLoopFilterTypes] = {
+      "89bb757faa44298b7f6e9c1a67f455a5",
+      "be75d5a2fcd83709ff0845f7d83f7006",
+  };
+  static const char* const kDigestsSize8[kNumLoopFilterTypes] = {
+      "b09137d68c7b4f8a8a15e33b4b69828f",
+      "ef8a7f1aa073805516d3518a82a5cfa4",
+  };
+  static const char* const kDigestsSize14[kNumLoopFilterTypes] = {
+      "6a7bc061ace0888275af88093f82ca08",
+      "a957ddae005839aa41ba7691788b01e4",
+  };
+
+  switch (size) {
+    case kLoopFilterSize4:
+      return kDigestsSize4;
+    case kLoopFilterSize6:
+      return kDigestsSize6;
+    case kLoopFilterSize8:
+      return kDigestsSize8;
+    case kLoopFilterSize14:
+      return kDigestsSize14;
+    default:
+      ADD_FAILURE() << "Unknown loop filter size" << size;
+      return nullptr;
+  }
+}
+
+TEST_P(LoopFilterTest8bpp, DISABLED_Speed) {
+  TestRandomValues(nullptr, kNumSpeedTests);
+}
+
+TEST_P(LoopFilterTest8bpp, FixedInput) {
+  TestRandomValues(GetDigests8bpp(size_), kNumTests);
+}
+
+TEST_P(LoopFilterTest8bpp, SaturatedValues) { TestSaturatedValues(); }
+
+constexpr LoopFilterSize kLoopFilterSizes[] = {
+    kLoopFilterSize4, kLoopFilterSize6, kLoopFilterSize8, kLoopFilterSize14};
+
+INSTANTIATE_TEST_SUITE_P(C, LoopFilterTest8bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, LoopFilterTest8bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, LoopFilterTest8bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+#endif
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using LoopFilterTest10bpp = LoopFilterTest<10, uint16_t>;
+
+const char* const* GetDigests10bpp(LoopFilterSize size) {
+  static const char* const kDigestsSize4[kNumLoopFilterTypes] = {
+      "72e75c478bb130ff1ebfa75f3a70b1a2",
+      "f32d67b611080e0bf1a9d162ff47c133",
+  };
+  static const char* const kDigestsSize6[kNumLoopFilterTypes] = {
+      "8aec73c60c87ac7cc6bc9cc5157a2795",
+      "0e4385d3a0cbb2b1551e05ad2b0f07fb",
+  };
+  static const char* const kDigestsSize8[kNumLoopFilterTypes] = {
+      "85cb2928fae43e1a27b2fe1b78ba7534",
+      "d044fad9d7c64b93ecb60c88ac48e55f",
+  };
+  static const char* const kDigestsSize14[kNumLoopFilterTypes] = {
+      "ebca95ec0db6efbac7ff7cbeabc0e6d0",
+      "754ffaf0ac26a5953a029653bb5dd275",
+  };
+
+  switch (size) {
+    case kLoopFilterSize4:
+      return kDigestsSize4;
+    case kLoopFilterSize6:
+      return kDigestsSize6;
+    case kLoopFilterSize8:
+      return kDigestsSize8;
+    case kLoopFilterSize14:
+      return kDigestsSize14;
+    default:
+      ADD_FAILURE() << "Unknown loop filter size" << size;
+      return nullptr;
+  }
+}
+
+TEST_P(LoopFilterTest10bpp, DISABLED_Speed) {
+  TestRandomValues(nullptr, kNumSpeedTests);
+}
+
+TEST_P(LoopFilterTest10bpp, FixedInput) {
+  TestRandomValues(GetDigests10bpp(size_), kNumTests);
+}
+
+TEST_P(LoopFilterTest10bpp, SaturatedValues) { TestSaturatedValues(); }
+
+INSTANTIATE_TEST_SUITE_P(C, LoopFilterTest10bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, LoopFilterTest10bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, LoopFilterTest10bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+//------------------------------------------------------------------------------
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using LoopFilterTest12bpp = LoopFilterTest<12, uint16_t>;
+
+const char* const* GetDigests12bpp(LoopFilterSize size) {
+  static const char* const kDigestsSize4[kNumLoopFilterTypes] = {
+      "a14599cbfe2daee633d556a15c47b1f6",
+      "1f0a0794832de1012e2fed6b1cb02e69",
+  };
+  static const char* const kDigestsSize6[kNumLoopFilterTypes] = {
+      "c76b24a73139239db10f16f36e01a625",
+      "3f75d904e9dcb1886e84a0f03f60f31e",
+  };
+  static const char* const kDigestsSize8[kNumLoopFilterTypes] = {
+      "57c6f0efe2ab3957f5500ca2a9670f37",
+      "caa1f90c2eb2b65b280d678f8fcf6be8",
+  };
+  static const char* const kDigestsSize14[kNumLoopFilterTypes] = {
+      "0c58f7466c36c3f4a2c1b4aa1b80f0b3",
+      "63077978326e6dddb5b2c3bfe6d684f5",
+  };
+
+  switch (size) {
+    case kLoopFilterSize4:
+      return kDigestsSize4;
+    case kLoopFilterSize6:
+      return kDigestsSize6;
+    case kLoopFilterSize8:
+      return kDigestsSize8;
+    case kLoopFilterSize14:
+      return kDigestsSize14;
+    default:
+      ADD_FAILURE() << "Unknown loop filter size" << size;
+      return nullptr;
+  }
+}
+
+TEST_P(LoopFilterTest12bpp, DISABLED_Speed) {
+  TestRandomValues(nullptr, kNumSpeedTests);
+}
+
+TEST_P(LoopFilterTest12bpp, FixedInput) {
+  TestRandomValues(GetDigests12bpp(size_), kNumTests);
+}
+
+TEST_P(LoopFilterTest12bpp, SaturatedValues) { TestSaturatedValues(); }
+
+INSTANTIATE_TEST_SUITE_P(C, LoopFilterTest12bpp,
+                         testing::ValuesIn(kLoopFilterSizes));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+
+static std::ostream& operator<<(std::ostream& os, const LoopFilterSize size) {
+  return os << ToString(size);
+}
+
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/loop_restoration_test.cc b/src/dsp/loop_restoration_test.cc
new file mode 100644
index 0000000..5c645b8
--- /dev/null
+++ b/src/dsp/loop_restoration_test.cc
@@ -0,0 +1,706 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/loop_restoration.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/common.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// in unit of Pixel.
+constexpr int kBorder = 16;
+constexpr int kWidth = 256;
+constexpr int kHeight = 255;
+constexpr int kStride = kWidth + 2 * kBorder;
+constexpr int kOffset = kBorder * kStride + kBorder;
+constexpr int kMaxBlockSize = 288 * kStride;
+constexpr int kUnitWidths[] = {32, 64, 128, 256};
+
+constexpr int kNumRadiusTypes = 3;
+constexpr int kNumWienerOrders = 4;
+constexpr int kWienerOrders[] = {7, 5, 3, 1};
+constexpr int kWienerOrderIdLookup[] = {0, 3, 0, 2, 0, 1, 0, 0};
+
+template <int bitdepth, typename Pixel>
+class SelfGuidedFilterTest : public testing::TestWithParam<int>,
+                             public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  SelfGuidedFilterTest() = default;
+  SelfGuidedFilterTest(const SelfGuidedFilterTest&) = delete;
+  SelfGuidedFilterTest& operator=(const SelfGuidedFilterTest&) = delete;
+  ~SelfGuidedFilterTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    LoopRestorationInit_C();
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        LoopRestorationInit_AVX2();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+        LoopRestorationInit10bpp_AVX2();
+#endif
+      }
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        LoopRestorationInit_SSE4_1();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+        LoopRestorationInit10bpp_SSE4_1();
+#endif
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      LoopRestorationInit_NEON();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      LoopRestorationInit10bpp_NEON();
+#endif
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    target_self_guided_filter_func_ = dsp->loop_restorations[1];
+    restoration_info_.type = kLoopRestorationTypeSgrProj;
+    memset(dst_, 0, sizeof(dst_));
+  }
+
+  void SetInputData(int type, Pixel value, int radius_index,
+                    libvpx_test::ACMRandom* rnd);
+  void TestFixedValues(int test_index, Pixel value);
+  void TestRandomValues(bool speed);
+
+ protected:
+  const int unit_width_ = GetParam();
+  const int unit_height_ = kRestorationUnitHeight;
+
+ private:
+  alignas(kMaxAlignment) Pixel src_[kMaxBlockSize];
+  alignas(kMaxAlignment) Pixel dst_[kMaxBlockSize];
+  RestorationUnitInfo restoration_info_;
+  RestorationBuffer restoration_buffer_;
+  LoopRestorationFunc target_self_guided_filter_func_;
+};
+
+template <int bitdepth, typename Pixel>
+void SelfGuidedFilterTest<bitdepth, Pixel>::SetInputData(
+    int type, Pixel value, int radius_index,
+    libvpx_test::ACMRandom* const rnd) {
+  const int mask = (1 << bitdepth) - 1;
+  if (type == 0) {  // Set fixed values
+    for (auto& s : src_) s = value;
+  } else {  // Set random values
+    for (auto& s : src_) s = rnd->Rand16() & mask;
+  }
+  for (auto& d : dst_) d = rnd->Rand16() & mask;
+  restoration_info_.sgr_proj_info.multiplier[0] =
+      kSgrProjMultiplierMin[0] +
+      rnd->PseudoUniform(kSgrProjMultiplierMax[0] - kSgrProjMultiplierMin[0] +
+                         1);
+  restoration_info_.sgr_proj_info.multiplier[1] =
+      kSgrProjMultiplierMin[1] +
+      rnd->PseudoUniform(kSgrProjMultiplierMax[1] - kSgrProjMultiplierMin[1] +
+                         1);
+  // regulate multiplier so that it matches libaom.
+  // Valid self-guided filter doesn't allow r0 and r1 to be 0 at the same time.
+  // When r0 or r1 is zero, its corresponding multiplier is set to zero in
+  // libaom.
+  int index;
+  if (radius_index == 0) {
+    index = 0;  // r0 = 2, r1 = 1
+  } else if (radius_index == 1) {
+    index = 10;  // r0 = 0, r1 = 1
+  } else /* if (radius_index == 2) */ {
+    index = 14;  // r0 = 2, r1 = 0
+  }
+  const uint8_t r0 = kSgrProjParams[index][0];
+  const uint8_t r1 = kSgrProjParams[index][2];
+  static constexpr int kMultiplier[2] = {0, 95};
+  restoration_info_.sgr_proj_info.index = index;
+  if (r0 == 0) {
+    restoration_info_.sgr_proj_info.multiplier[0] = kMultiplier[0];
+  } else if (r1 == 0) {
+    restoration_info_.sgr_proj_info.multiplier[1] = kMultiplier[1];
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void SelfGuidedFilterTest<bitdepth, Pixel>::TestFixedValues(int test_index,
+                                                            Pixel value) {
+  static const char* const kDigest[][3][kNumRadiusTypes] = {
+      {{"7b78783ff4f03625a50c2ebfd574adca", "4faa0810639016f11a9f761ce28c38b0",
+        "a03314fc210bee68c7adbb44d2bbdac7"},
+       {"fce031d1339cfef5016e76a643538a71", "d439e1060de3f07b5b29c9b0b7c08e54",
+        "a6583fe9359877f4a259c81d900fc4fb"},
+       {"8f9b6944c8965f34d444a667da3b0ebe", "84fa62c491c67c3a435fd5140e7a4f82",
+        "d04b62d97228789e5c6928d40d5d900e"}},
+      {{"948ea16a90c4cefef87ce5b0ee105fc6", "76740629877b721432b84dbbdb4e352a",
+        "27100f37b3e42a5f2a051e1566edb6f8"},
+       {"dd320de3bc82f4ba69738b2190ea9f85", "bf82f271e30a1aca91e53b086e133fb3",
+        "69c274ac59c99999e1bfbf2fc4586ebd"},
+       {"86ff2318bf8a584b8d5edd710681d621", "f6e1c104a764d6766cc278d5b216855a",
+        "6d928703526ab114efba865ff5b11886"}},
+      {{"9fbf1b246011250f38532a543cc6dd74", "d5c1e0142390ebb51b075c49f8ee9ff4",
+        "92f31086ba2f9e1508983b22d93a4e5c"},
+       {"2198321e6b95e7199738e60f5ddc6966", "34f74626027ffca010c824ddf0942b13",
+        "43dd7df2c2a601262c68cd8af1c61b82"},
+       {"1ab6138c3a82ac8ccd840f0553fdfb58", "be3bf92633f7165d3ad9c327d2dd53fe",
+        "41115efff3adeb541e04db23faa22f23"}},
+      {{"42364ff8dbdbd6706fa3b8855a4258be", "a7843fdfd4d3c0d80ba812b353b4d6b4",
+        "f8a6a025827f29f857bed3e28ba3ea33"},
+       {"b83c1f8d7712e37f9b21b033822e37ed", "589daf2e3e6f8715873920515cfc1b42",
+        "20dcbe8e317a4373bebf11d56adc5f02"},
+       {"7971a60337fcdb662c92db051bd0bb41", "75f89f346c2a37bf0c6695c0482531e6",
+        "1595eeacd62cdce4d2fb094534c22c1e"}}};
+  if (target_self_guided_filter_func_ == nullptr) return;
+  ASSERT_LT(value, 1 << bitdepth);
+  constexpr int bd_index = (bitdepth - 8) / 2;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  const Pixel* const src = src_ + kOffset;
+  Pixel* const dst = dst_ + kOffset;
+  for (int radius_index = 0; radius_index < kNumRadiusTypes; ++radius_index) {
+    SetInputData(0, value, radius_index, &rnd);
+    const absl::Time start = absl::Now();
+    for (int y = 0; y < kHeight; y += unit_height_) {
+      const int height = std::min(unit_height_, kHeight - y);
+      for (int x = 0; x < kWidth; x += unit_width_) {
+        const int width = std::min(unit_width_, kWidth - x);
+        const Pixel* const source = src + y * kStride + x;
+        target_self_guided_filter_func_(
+            restoration_info_, source, kStride,
+            source - kRestorationVerticalBorder * kStride, kStride,
+            source + height * kStride, kStride, width, height,
+            &restoration_buffer_, dst + y * kStride + x);
+      }
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    test_utils::CheckMd5Digest(
+        "kLoopRestorationTypeSgrProj", std::to_string(GetParam()).c_str(),
+        kDigest[test_index][bd_index][radius_index], dst_ + kBorder * kStride,
+        kHeight * kStride * sizeof(*dst_), elapsed_time);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void SelfGuidedFilterTest<bitdepth, Pixel>::TestRandomValues(bool speed) {
+  static const char* const kDigest[][3][kNumRadiusTypes] = {
+      {{"9f8358ed820943fa0abe3a8ebb5887db", "fb5d48870165522341843bcbfa8674fb",
+        "ca67159cd29475ac5d52ca4a0df3ea10"},
+       {"a78641886ea0cf8757057d1d91e01434", "1b95172a5f2f9c514c78afa4cf8e5678",
+        "a8ba988283d9e1ad1f0dcdbf6bbdaade"},
+       {"d95e98d031f9ba290e5183777d1e4905", "f806853cfadb50e6dbd4898412b92934",
+        "741fbfdb79cda695afedda3d51dbb27f"}},
+      {{"f219b445e5c80ffb5dd0359cc2cb4dd4", "699b2c9ddca1cbb0d4fc24cbcbe951e9",
+        "a4005899fa8d3c3c4669910f93ff1290"},
+       {"10a75cab3c78b891c8c6d92d55f685d1", "d46f158f57c628136f6f298ee8ca6e0e",
+        "07203ad761775d5d317f2b7884afd9fe"},
+       {"76b9ef906090fa81af64cce3bba0a54a", "8eecc59acdef8953aa9a96648c0ccd2c",
+        "6e45a0ef60e0475f470dc93552047f07"}},
+      {{"000d4e382be4003b514c9135893d0a37", "8fb082dca975be363bfc9c2d317ae084",
+        "475bcb6a58f87da7723f6227bc2aca0e"},
+       {"4d589683f69ccc5b416149dcc5c835d5", "986b6832df1f6020d50be61ae121e42f",
+        "7cb5c5dbdb3d1c54cfa00def450842dc"},
+       {"0e3dc23150d18c9d366d15e174727311", "8495122917770d822f1842ceff987b03",
+        "4aeb9db902072cefd6af0aff8aaabd24"}},
+      {{"fd43bfe34d63614554dd29fb24b12173", "5c1ba74ba3062c769d5c3c86a85ac9b9",
+        "f1eda6d15b37172199d9949c2315832f"},
+       {"a11be3117fb77e8fe113581b06f98bd1", "df94d12b774ad5cf744c871e707c36c8",
+        "b23dc0b54c3500248d53377030428a61"},
+       {"9c331f2b9410354685fe904f6c022dfa", "b540b0045b7723fbe962fd675db4b077",
+        "3cecd1158126c9c9cc2873ecc8c1a135"}},
+      {{"f3079b3b21d8dc6fce7bb1fd104be359", "c6fcbc686cfb97ab3a64f445d73aad36",
+        "23966cba3e0e7803eeb951905861e0dd"},
+       {"7210391a6fe26e5ca5ea205bc38aa035", "4c3e6eccad3ea152d320ecd1077169de",
+        "dcee48f94126a2132963e86e93dd4903"},
+       {"beb3dd8a2dbc5f83ef171b0ffcead3ab", "c373bd9c46bdb89a3d1e41759c315025",
+        "cd407b212ab46fd4a451d5dc93a0ce4a"}}};
+  if (target_self_guided_filter_func_ == nullptr) return;
+  constexpr int bd_index = (bitdepth - 8) / 2;
+  const int num_inputs = speed ? 1 : 5;
+#if LIBGAV1_ENABLE_NEON
+  const int num_tests = speed ? 4000 : 1;
+#else
+  const int num_tests = speed ? 10000 : 1;
+#endif
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  const Pixel* const src = src_ + kOffset;
+  Pixel* const dst = dst_ + kOffset;
+  for (int i = 0; i < num_inputs; ++i) {
+    for (int radius_index = 0; radius_index < kNumRadiusTypes; ++radius_index) {
+      SetInputData(1, 0, radius_index, &rnd);
+      const absl::Time start = absl::Now();
+      for (int k = 0; k < num_tests; ++k) {
+        for (int y = 0; y < kHeight; y += unit_height_) {
+          const int height = std::min(unit_height_, kHeight - y);
+          for (int x = 0; x < kWidth; x += unit_width_) {
+            const int width = std::min(unit_width_, kWidth - x);
+            const Pixel* const source = src + y * kStride + x;
+            target_self_guided_filter_func_(
+                restoration_info_, source, kStride,
+                source - kRestorationVerticalBorder * kStride, kStride,
+                source + height * kStride, kStride, width, height,
+                &restoration_buffer_, dst + y * kStride + x);
+          }
+        }
+      }
+      const absl::Duration elapsed_time = absl::Now() - start;
+      test_utils::CheckMd5Digest(
+          "kLoopRestorationTypeSgrProj", std::to_string(GetParam()).c_str(),
+          kDigest[i][bd_index][radius_index], dst_ + kBorder * kStride,
+          kHeight * kStride * sizeof(*dst_), elapsed_time);
+    }
+  }
+}
+
+using SelfGuidedFilterTest8bpp = SelfGuidedFilterTest<8, uint8_t>;
+
+TEST_P(SelfGuidedFilterTest8bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 128);
+  TestFixedValues(3, 255);
+  TestRandomValues(false);
+}
+
+TEST_P(SelfGuidedFilterTest8bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, SelfGuidedFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, SelfGuidedFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, SelfGuidedFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using SelfGuidedFilterTest10bpp = SelfGuidedFilterTest<10, uint16_t>;
+
+TEST_P(SelfGuidedFilterTest10bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 512);
+  TestFixedValues(3, 1023);
+  TestRandomValues(false);
+}
+
+TEST_P(SelfGuidedFilterTest10bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, SelfGuidedFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, SelfGuidedFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, SelfGuidedFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using SelfGuidedFilterTest12bpp = SelfGuidedFilterTest<12, uint16_t>;
+
+TEST_P(SelfGuidedFilterTest12bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 2048);
+  TestFixedValues(3, 4095);
+  TestRandomValues(false);
+}
+
+TEST_P(SelfGuidedFilterTest12bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+INSTANTIATE_TEST_SUITE_P(C, SelfGuidedFilterTest12bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+template <int bitdepth, typename Pixel>
+class WienerFilterTest : public testing::TestWithParam<int>,
+                         public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  WienerFilterTest() = default;
+  WienerFilterTest(const WienerFilterTest&) = delete;
+  WienerFilterTest& operator=(const WienerFilterTest&) = delete;
+  ~WienerFilterTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    LoopRestorationInit_C();
+    const Dsp* const dsp = GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    base_wiener_filter_func_ = dsp->loop_restorations[0];
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "AVX2/")) {
+      if ((GetCpuInfo() & kAVX2) != 0) {
+        LoopRestorationInit_AVX2();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+        LoopRestorationInit10bpp_AVX2();
+#endif
+      }
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        LoopRestorationInit_SSE4_1();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+        LoopRestorationInit10bpp_SSE4_1();
+#endif
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      LoopRestorationInit_NEON();
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      LoopRestorationInit10bpp_NEON();
+#endif
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    target_wiener_filter_func_ = dsp->loop_restorations[0];
+    restoration_info_.type = kLoopRestorationTypeWiener;
+    memset(dst_, 0, sizeof(dst_));
+    memset(tmp_, 0, sizeof(tmp_));
+    memset(buffer_, 0, sizeof(buffer_));
+  }
+
+  static void CleanFilterByOrder(const int order,
+                                 int16_t filter[kWienerFilterTaps]) {
+    if (order <= 5) filter[0] = 0;
+    if (order <= 3) filter[1] = 0;
+    if (order <= 1) filter[2] = 0;
+  }
+
+  void SetInputData(int type, Pixel value, int vertical_order,
+                    int horizontal_order);
+  void TestFixedValues(int digest_id, Pixel value);
+  void TestRandomValues(bool speed);
+  void TestCompare2C();
+
+ protected:
+  const int unit_width_ = GetParam();
+  const int unit_height_ = kRestorationUnitHeight;
+
+ private:
+  alignas(kMaxAlignment)
+      uint16_t buffer_[(kRestorationUnitWidth + kWienerFilterTaps - 1) *
+                       kRestorationUnitHeight];
+  alignas(kMaxAlignment) Pixel src_[kMaxBlockSize];
+  alignas(kMaxAlignment) Pixel dst_[kMaxBlockSize];
+  alignas(kMaxAlignment) Pixel tmp_[kMaxBlockSize];
+  RestorationUnitInfo restoration_info_;
+  RestorationBuffer restoration_buffer_;
+  LoopRestorationFunc base_wiener_filter_func_;
+  LoopRestorationFunc target_wiener_filter_func_;
+};
+
+template <int bitdepth, typename Pixel>
+void WienerFilterTest<bitdepth, Pixel>::SetInputData(
+    int type, Pixel value, const int vertical_order,
+    const int horizontal_order) {
+  const int mask = (1 << bitdepth) - 1;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  if (type == 0) {
+    for (auto& s : src_) s = value;
+  } else {
+    for (auto& s : src_) s = rnd.Rand16() & mask;
+  }
+  int order = vertical_order;
+  for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
+    auto& filter = restoration_info_.wiener_info.filter[i];
+    filter[3] = 128;
+    for (int j = 0; j < 3; ++j) {
+      filter[j] = kWienerTapsMin[j] +
+                  rnd.PseudoUniform(kWienerTapsMax[j] - kWienerTapsMin[j] + 1);
+    }
+    CleanFilterByOrder(order, filter);
+    filter[3] -= 2 * (filter[0] + filter[1] + filter[2]);
+    restoration_info_.wiener_info.number_leading_zero_coefficients[i] =
+        (kWienerFilterTaps - order) / 2;
+    order = horizontal_order;
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void WienerFilterTest<bitdepth, Pixel>::TestFixedValues(int digest_id,
+                                                        Pixel value) {
+  static const char* const kDigest[3][4] = {
+      {"74fc90760a14b13340cb718f200ba350", "5bacaca0128cd36f4805330b3787771d",
+       "1109e17545cc4fbd5810b8b77e19fc36", "e7f914ec9d065aba92338016e17a526c"},
+      {"c8cc38790ceb0bea1eb989686755e1e5", "70f573b7e8875262c638a68d2f317916",
+       "193b19065899c835cb513149eb36d135", "f1dff65e3e53558b303ef0a2e3f3ba98"},
+      {"c8cc38790ceb0bea1eb989686755e1e5", "70f573b7e8875262c638a68d2f317916",
+       "961eeb92bd9d85eb47e3961ee93d279a", "039a279232bc90eebc0ec2fe3e18a7e1"},
+  };
+  if (target_wiener_filter_func_ == nullptr) return;
+  ASSERT_LT(value, 1 << bitdepth);
+  constexpr int bd_index = (bitdepth - 8) / 2;
+  const Pixel* const src = src_ + kOffset;
+  Pixel* const dst = dst_ + kOffset;
+  for (const auto vertical_order : kWienerOrders) {
+    for (const auto horizontal_order : kWienerOrders) {
+      SetInputData(0, value, vertical_order, horizontal_order);
+      memset(dst_, 0, sizeof(dst_));
+      const absl::Time start = absl::Now();
+      for (int y = 0; y < kHeight; y += unit_height_) {
+        const int height = std::min(unit_height_, kHeight - y);
+        for (int x = 0; x < kWidth; x += unit_width_) {
+          const int width = std::min(unit_width_, kWidth - x);
+          const Pixel* const source = src + y * kStride + x;
+          target_wiener_filter_func_(
+              restoration_info_, source, kStride,
+              source - kRestorationVerticalBorder * kStride, kStride,
+              source + height * kStride, kStride, width, height,
+              &restoration_buffer_, dst + y * kStride + x);
+        }
+      }
+      const absl::Duration elapsed_time = absl::Now() - start;
+      test_utils::CheckMd5Digest(
+          "kLoopRestorationTypeWiener", std::to_string(GetParam()).c_str(),
+          kDigest[bd_index][digest_id], dst_, sizeof(dst_), elapsed_time);
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void WienerFilterTest<bitdepth, Pixel>::TestRandomValues(bool speed) {
+  static const char* const kDigest[3][kNumWienerOrders][kNumWienerOrders] = {
+      {{"40d0cf56d2ffb4f581e68b0fc97f547f", "5c04745209b684ba98004ebb0f64e70b",
+        "545ed7d3f7e7ca3b86b4ada31f7aaee7", "0d6b2967f1bd1d99b720e563fe0cf03f"},
+       {"44b37076f0cf27f6eb506aca50c1d3e4", "e927d64dc9249e05a65e10ee75baa7d9",
+        "6136ecb4e29b17c9566504148943fd47", "c5ee2da81d44dc8cb2ac8021f724eb7a"},
+       {"125cbb227313ec91a2683f26e6f049d1", "77671b6529c806d23b749f304b548f59",
+        "28d53a1b486881895b8f73fa64486df1", "f5e32165bafe575d7ee7a6fbae75f36d"},
+       {"e832c41f2566ab542b32abba9d4f27bd", "ab1336ee6b85cba651f35ee5d3b3cc5c",
+        "52a673b6d14fbdca5ebdb1a34ee3326f",
+        "ebb42c7c9111f2e39f21e2158e801d9e"}},
+      {{"8cd9c6bd9983bd49564a58ed4af9098a", "f71f333c9d71237ed4e46f0ef2283196",
+        "375b43abc1d6682d62f91c1841b8b0fc", "71e2444822ae9c697ddfc96e07c6e8a1"},
+       {"d9ed3a66ceef405c08c87f6e91b71059", "c171fcff5fb7bb919f13ead7a4917a4c",
+        "8fbd1edb82fcd78d4d286886f65a700a", "fe14a143e6b261c5bb07b179d40be5a2"},
+       {"1c995f4e7f117857de73211b81093bd0", "5ab1ee3bb14adcd66d66802d58bee068",
+        "d77430783e173ebd1b30e5d9336c8b69", "e159a3620747458dff7ed3d20da1a4b7"},
+       {"5346fa07d195c257548a332753b057a3", "c77674bc0a638abc4d38d58e494fc7cf",
+        "7cbc1562a9dd08e1973b3b9ac1afc765",
+        "3c91bf1a34672cd40bf261c5820d3ec3"}},
+      {{"501b57370c781372b514accd03d161af", "a4569b5eff7f7e8b696934d192619be5",
+        "24eb2aa43118a8822f7a6a7384ab9ea7", "edd7ac227733b5a4496bfdbdf4eb34d7"},
+       {"77624cf73299a1bd928eae3eb8945dbe", "b3f311cacbf45fa892761462d31b2598",
+        "977c063d93a4b95cb365363763faa4da", "02313c9d360a1e0180ed05d3e4444c3d"},
+       {"f499655ecdcbe0ac48553f1eee758589", "a009c83c03e47cbd05c1243e28579bd9",
+        "d5f0b4fd761ff51efce949e6c5ec4833", "e3a9a57aacd2e6cfe0f792a885b3e0e3"},
+       {"b4cf906e9bb02ffca15c1e9575962ca2", "d0ca9f933978c0c31175ba1b28a44ae8",
+        "81ac1475530ffbd1c8d3ce7da87ffe6b",
+        "b96412949c2e31b29388222ac8914fa2"}},
+  };
+  if (target_wiener_filter_func_ == nullptr) return;
+  constexpr int bd_index = (bitdepth - 8) / 2;
+#if LIBGAV1_ENABLE_NEON
+  const int num_tests = speed ? 5000 : 1;
+#else
+  const int num_tests = speed ? 10000 : 1;
+#endif
+  const Pixel* const src = src_ + kOffset;
+  Pixel* const dst = dst_ + kOffset;
+  for (const auto vertical_order : kWienerOrders) {
+    for (const auto horizontal_order : kWienerOrders) {
+      SetInputData(1, (1 << bitdepth) - 1, vertical_order, horizontal_order);
+      memset(dst_, 0, sizeof(dst_));
+      const absl::Time start = absl::Now();
+      for (int i = 0; i < num_tests; ++i) {
+        for (int y = 0; y < kHeight; y += unit_height_) {
+          const int height = std::min(unit_height_, kHeight - y);
+          for (int x = 0; x < kWidth; x += unit_width_) {
+            const int width = std::min(unit_width_, kWidth - x);
+            const Pixel* const source = src + y * kStride + x;
+            target_wiener_filter_func_(
+                restoration_info_, source, kStride,
+                source - kRestorationVerticalBorder * kStride, kStride,
+                source + height * kStride, kStride, width, height,
+                &restoration_buffer_, dst + y * kStride + x);
+          }
+        }
+      }
+      const absl::Duration elapsed_time = absl::Now() - start;
+      test_utils::CheckMd5Digest(
+          "kLoopRestorationTypeWiener", std::to_string(GetParam()).c_str(),
+          kDigest[bd_index][kWienerOrderIdLookup[vertical_order]]
+                 [kWienerOrderIdLookup[horizontal_order]],
+          dst_, sizeof(dst_), elapsed_time);
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void WienerFilterTest<bitdepth, Pixel>::TestCompare2C() {
+  if (base_wiener_filter_func_ == nullptr) return;
+  if (target_wiener_filter_func_ == nullptr) return;
+  if (base_wiener_filter_func_ == target_wiener_filter_func_) return;
+  const Pixel* const src = src_ + kOffset;
+  Pixel* const dst = dst_ + kOffset;
+  Pixel* const tmp = tmp_ + kOffset;
+  for (const auto vertical_order : kWienerOrders) {
+    for (const auto horizontal_order : kWienerOrders) {
+      SetInputData(1, (1 << bitdepth) - 1, vertical_order, horizontal_order);
+      for (int x = 0; x < 2; ++x) {
+        // Prepare min/max filter coefficients.
+        int order = vertical_order;
+        for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
+          auto& filter = restoration_info_.wiener_info.filter[i];
+          for (int j = 0; j < 3; ++j) {
+            filter[j] = (x == 0) ? kWienerTapsMin[j] : kWienerTapsMax[j];
+          }
+          CleanFilterByOrder(order, filter);
+          filter[3] = 128 - 2 * (filter[0] + filter[1] + filter[2]);
+          restoration_info_.wiener_info.number_leading_zero_coefficients[i] =
+              (kWienerFilterTaps - order) / 2;
+          order = horizontal_order;
+        }
+        base_wiener_filter_func_(restoration_info_, src, kStride,
+                                 src - kRestorationVerticalBorder * kStride,
+                                 kStride, src + unit_height_ * kStride, kStride,
+                                 unit_width_, unit_height_,
+                                 &restoration_buffer_, dst);
+        target_wiener_filter_func_(restoration_info_, src, kStride,
+                                   src - kRestorationVerticalBorder * kStride,
+                                   kStride, src + unit_height_ * kStride,
+                                   kStride, unit_width_, unit_height_,
+                                   &restoration_buffer_, tmp);
+        if (!test_utils::CompareBlocks(dst, tmp, unit_width_, unit_height_,
+                                       kStride, kStride, false, true)) {
+          ADD_FAILURE() << "Mismatch -- wiener taps min/max";
+        }
+      }
+    }
+  }
+}
+
+using WienerFilterTest8bpp = WienerFilterTest<8, uint8_t>;
+
+TEST_P(WienerFilterTest8bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 128);
+  TestFixedValues(3, 255);
+  TestRandomValues(false);
+}
+
+TEST_P(WienerFilterTest8bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+TEST_P(WienerFilterTest8bpp, TestCompare2C) { TestCompare2C(); }
+
+INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, WienerFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, WienerFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WienerFilterTest8bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using WienerFilterTest10bpp = WienerFilterTest<10, uint16_t>;
+
+TEST_P(WienerFilterTest10bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 512);
+  TestFixedValues(3, 1023);
+  TestRandomValues(false);
+}
+
+TEST_P(WienerFilterTest10bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+TEST_P(WienerFilterTest10bpp, TestCompare2C) { TestCompare2C(); }
+
+INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+
+#if LIBGAV1_ENABLE_AVX2
+INSTANTIATE_TEST_SUITE_P(AVX2, WienerFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, WienerFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WienerFilterTest10bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using WienerFilterTest12bpp = WienerFilterTest<12, uint16_t>;
+
+TEST_P(WienerFilterTest12bpp, Correctness) {
+  TestFixedValues(0, 0);
+  TestFixedValues(1, 1);
+  TestFixedValues(2, 2048);
+  TestFixedValues(3, 4095);
+  TestRandomValues(false);
+}
+
+TEST_P(WienerFilterTest12bpp, DISABLED_Speed) { TestRandomValues(true); }
+
+TEST_P(WienerFilterTest12bpp, TestCompare2C) { TestCompare2C(); }
+
+INSTANTIATE_TEST_SUITE_P(C, WienerFilterTest12bpp,
+                         testing::ValuesIn(kUnitWidths));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/mask_blend_test.cc b/src/dsp/mask_blend_test.cc
new file mode 100644
index 0000000..29dd43b
--- /dev/null
+++ b/src/dsp/mask_blend_test.cc
@@ -0,0 +1,602 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/mask_blend.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kNumSpeedTests = 50000;
+// mask_blend is applied to compound prediction values when is_inter_intra is
+// false. This implies a range far exceeding that of pixel values. The ranges
+// include kCompoundOffset in 10bpp and 12bpp.
+// see: src/dsp/convolve.cc & src/dsp/warp.cc.
+constexpr int kCompoundPredictionRange[3][2] = {
+    // 8bpp
+    {-5132, 9212},
+    // 10bpp
+    {3988, 61532},
+    // 12bpp
+    {3974, 61559},
+};
+
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigest[] = {
+      "4b70d5ef5ac7554b4b2660a4abe14a41", "64adb36f07e4a2c4ea4f05cfd715ff58",
+      "2cd162cebf99724a3fc22d501bd8c8e4", "c490478208374a43765900ef7115c264",
+      "b98f222eb70ef8589da2d6c839ca22b8", "54752ca05f67b5af571bc311aa4e3de3",
+      "5ae48814dd285bfca4f5ee8e339dca99", "383f3f4f47563f065d1b6068e5931a24",
+      "344b2dab7accd8bd0a255bee16207336", "0b2f6f755d1547eea7e0172f8133ea01",
+      "310dc6364fdacba186c01f0e8ac4fcb7", "c2ee4673078d34971319c77ca77b23d1",
+      "b0c9f08b73d9e5c16eaf5abdbca1fdc0", "eaad805999d949fa1e1bbbb63b4b7827",
+      "6eb2a80d212df89403efb50db7a81b08", "c30730aa799dba78a2ebd3f729af82c7",
+      "4346c2860b23f0072b6b288f14c1df36", "1cdace53543063e129a125c4084ca5d7",
+      "1ae5328e0c0f4f2bec640d1af03b2978", "3860e040fbee0c5f68f0b4af769209b3",
+      "e9480ded15d9c38ee19bf5fa816dd296", "4e17c222b64f428df29938a8120ca256",
+      "2a943bc6de9b29c8bcae189ad3bec276", "b5a6bc02c76fa61040678fb2c6c112d2",
+      "2c11bb9bd29c5577194edb77cfd1c614", "31ed1832810ae385f4ad8f57795dde1e",
+      "eb87d647839c33984dfb25bac0e7cdb3", "f652ec2b1478e35acb19cf28042ee849",
+      "0cfb18ac0cb94af1447bcac32ac20c36", "e152bbbf5ee4b40b7b41ec1f2e901aaa",
+      "f17f78fd485f7beafa8126c1cda801d7", "9f9fbee0cc9d99435efd3dff644be273",
+      "9b498843d66440c1e68dc7ab04f57d42", "2f2b0beceb31b79ccb9179991629e4b8",
+      "e06a6ebb6791529bb23fe5b0a9914220", "2b3d1ff19812a17c17b1be1f1727815e",
+      "d0bbdecec414950ed63a8a35c2bae397", "8e53906c6513058d7f17013fe0d32bf1",
+      "be0690efd31f0bf3c2adcd27ca011ed5", "c2b26243c5f147fdeadf52735aa68fb5",
+      "94bb83e774d9189c5ee04fb361855e19", "dad6441e723791a91f31a56b2136fd33",
+      "10ccac76a2debb842a0685a527b6a659", "346fb0a4914b64dda3ca0f521412b999",
+      "d7e400b855502bbb4f2b8294e207bb96", "3487503f2d73ec52f25b5e8d06c81da4",
+      "3f49c096acfcf46d44ce18b48debca7c", "8ed6a745a2b5457ac7f3ac145ce57e72",
+      "21f9dda5ef934a5ee6274b22cc22f93b", "507b60611afeb373384d9b7606f7ea46",
+      "ac766fadcdb85a47ad14a6846b9e5c36", "fde149bc2162e02bbc5fa85cc41641a5",
+      "f5f094b5742d0a920ba734b017452d24", "c90d06b0c76a0983bd1428df2a1b64b3",
+      "3649e6a6ed9f69e3f78e0b75160fb82a", "1d44b7649497e651216db50d325e3073",
+      "948fa112e90e3ca4d15f3d2f2acfab9a", "9bb54c0f7d07c0b44c44ba09379a04ff",
+      "228261ab6f098f489a8968cff1e1f7ae", "5e128db7462164f7327d1d8feeb2e4c7",
+      "9e8b97f6d9d482d5770b138bd1077747", "81563d505a4e8dd779a089abf2a28b77",
+      "b7157451de7cfa161dff1afd7f9b8622", "6a25cc0a4aaf8a315d1158dbb0ec2966",
+      "303867ee010ba51da485ee10149c6f9b", "63b64b7527d2476e9ae5139b8166e8c9",
+      "cfa93c2aeeb27a1190a445a6fee61e15", "804bcff8709665eed6830e24346101be",
+      "829947ed3e90776cda4ae82918461497", "1df10a1cb80c1a81f521e7e0f80b4f99",
+      "3c9593e42ac574f3555bb8511d438a54", "eecef71492c0626685815e646f728f79",
+      "0c43d59f456ddca2449e016ae4e34be7", "207d4ac2579f1271fc9eca8d743917b3",
+      "3c472bb0b1c891ffda19077ebb659e48", "a4ae7a0d25113bc0238fa27409f9c0dd",
+      "e8ad037ca81f46774bb01d20f46671ce", "b22741e4fe0e4062e40a2decec102ffd",
+      "c72f9e7bc0170163cb94da0faa0d3ffb", "accaf5d475d155cbd3a8c113f90718bc",
+      "2fd31e72444ea258380c16881580de81", "8a6a2a253f6f5b0ff75ba39488e6b082",
+      "c5e8159c0f3ebb7536e84ab3dadac1b3", "ef7ec20b46c7dcf16591835642bd68ef",
+      "0c3425399dc64870d726c2837666a55e", "0365029ffbfc4cedf3bf2d757ea5b9df",
+      "836aa403254af2e04d4b7a7c4db8bfc5", "7f2f3f9c91677b233795169f9a88b2b2",
+      "9fc8bbe787244dac638c367b9c611d13", "f66ef45fae8e163ab0f0f393531dad26",
+      "beb984e88b6f9b96ae6efe5da23ad16b", "1083b829ea766b1d4eb0bb96e9fb3bff",
+      "be8abad1da69e4d238a45fc02a0061cf",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigest[] = {
+      "1af3cbd1616941b59e6a3f6a417b6312", "1d8b3f4b9d5d2f4ff5be8e81b7243121",
+      "e767350f150a84ac5a06dc348e815d62", "53a3a76bf2bcd5761cd15fc739a4f4e1",
+      "7597f69dc19a584280be0d67911db6a6", "e1221c172843dc6c1b345bcd370771cc",
+      "1a640c71ff9bb45505d89761f19efa8f", "e192f64322e0edb250b52f63aaa4de97",
+      "2ccbe012ca167114b14c3ba70befa960", "0f68632d7e5faddb4554ca430d1df822",
+      "8caa0061a26e142b783951d5abd7bf5d", "b01eeed3ec549e4a593100d9c5ba587a",
+      "1cce6acdbd8ca8d2546ba937584730bf", "022913e87a3c1a86aaefe2c2d4f89882",
+      "48f8ab636ba15a06731d869b603cbe58", "ba1616c990d224c20de123c3ccf19952",
+      "346a797b7cb4de10759e329f8b49e077", "d4929154275255f2d786d6fc42c7c5d3",
+      "18a6af6f36ca1ea4ab6f5a76505de040", "0c43e68414bfc02f9b20e796506f643b",
+      "9f483f543f6b1d58e23abf9337ed6fe6", "e114860c2538b63f1be4a23560420cdc",
+      "da8680798f96572c46155c7838b452c3", "20b47a27617297231843c0f2ed7b559b",
+      "16fa4a4f33a32e28c79da83dca63fd41", "76e2c1d3c323777a3c478e11e1ba6bf2",
+      "dccdfd52a71855cc4da18af52bda4c03", "121befbd6c246e85a34225241b8bcaf1",
+      "5780757555fd87ca1ff3f1b498a1d6e9", "6b0be2256285694b1edc0201608e1326",
+      "b7ef338c58d17f69426b5a99170c7295", "b92b84b5b3d01afac02fb9c092e84b06",
+      "e6ef7fea8b183f871c4306c4f49370c5", "c1bf95c05774d8471504e57a3efa66e4",
+      "bbacdbdafc625a139361ec22fe2cf003", "5fbbb2d6ca8fc6d07ca8d4105fda4a01",
+      "c1cbb295d9f00aa865d91a95e96f99b2", "1490e4f2c874a76ecc2bbf35dce446c3",
+      "c3bd73daaeec39895a8b64812773c93c", "6d385068ef3afbd821183d36851f709b",
+      "a34c52ef7f2fd04d1cd420238641ef48", "45d10029358c6835cf968a30605659ea",
+      "a72c1bb18cf9312c5713ce0de370743d", "df7368db2a7515a1c06a4c9dd9e32ebf",
+      "52782632271caccfa9a35ed7533e2052", "6f0ef9b62d2b9956a6464694b7a86b79",
+      "814dbc176f7201725a1cfd1cf668b4b9", "065ffbee984f4b9343c8acb0eb04fcbe",
+      "0915d76ce458d5164e3c90c1ce150795", "bf2b431d9bfa7a9925ea6f6509267ae9",
+      "d3df8c0c940a01b7bf3c3afb80b6dcd4", "15ab86216c9856a8427a51fe599258a3",
+      "2cb078484472c88e26b7401c9f11cf51", "7c5f68cc098c8adabc9e26f9cd549151",
+      "a8e47da1fcc91c2bc74d030892621576", "71af422ba2d86a401f8278591c0ef540",
+      "964c902bb4698ce82f4aa0a1edc80cd6", "78271c37d62af86576dab72ed59746b3",
+      "7247c3a7534a41137027e7d3f255f5ef", "8e529ab964f5f9d0f7c3ced98239cfc8",
+      "2481ed50bff6b36a3cac6dca2aca5ae5", "78a1ff18bf217d45f5170675dee26948",
+      "00fc534119c13aa7af4b818cad9218a2", "67501a83c93f2f9debfa86955bdffde5",
+      "2a512ef738e33a4d8476f72654deffb4", "f4eef28078bbc12de9cfb5bc2fef6238",
+      "b7ac3a35205a978bed587356155bae0e", "51ea101f09c4de2f754b61ab5aff1526",
+      "2bd689d7ec964ee8c8f6f0682f93f5ca", "eecac8dbdaa73b8b3c2234892c444147",
+      "cb7086f44ef70ef919086a3d200d8c13", "0abe35e3c796c2de1e550426b2b19441",
+      "0eb140561e1ea3843464a5247d8ecb18", "d908f7317f00daacbe3dd43495db64ad",
+      "d4d677c4b347de0a13ccab7bc16b8e6e", "26523c2c2df7f31896a3ae5aa24d5ada",
+      "0ebb9f816684769816b2ae0b1f94e3a4", "fd938d0577e3687b0a810e199f69f0bb",
+      "eb8fb832e72030e2aa214936ae0effe4", "56631887763f7daf6e1e73783e5ff656",
+      "590a25cc722c2aa4d885eede5ef09f20", "80944a218ed9b9b0374cde72914449eb",
+      "d9cbc2f1e0e56cdd6722310932db1981", "a88eb213b7a6767bbe639cda120a4ab6",
+      "9972ecbadfdf3ed0b3fedf435c5a804f", "01fdf7e22405a1b17a8d275b7451094f",
+      "6a7824e10406fade0d032e886bbc76b6", "76fefadd793ec3928e915d92782bc7e1",
+      "0fbd6b076752c9f5c926ca5c1df892ac", "aac9457239f07ad633fcd45c1465af2a",
+      "56823ef9a8e21c9c7441cc9ed870d648", "52f4c7a0b7177175302652cbc482f442",
+      "f4a4f4d7c8b93c0486cf3cbaa26fbc19",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigest[] = {
+      "79a505b3877177197c94f0faeb0c9ec6", "cd22657d242f30c88bb83eae9efbbcce",
+      "c4c60a60976d119df3832ff6956e0181", "796bd78bf2346e8dfd61cecbf508ea0e",
+      "79e06cc6f880daf6cdb59b9b3a8efe1c", "f0643108e6b57bd566bc0d47b2dc64a1",
+      "8272a471e538ca469eaf5c997309589c", "3094741b63a29925da83dc1dc187654a",
+      "d0141df80f2335ed6051397cb2a5bc61", "33d9fd317b74f4572afbe004f991ca83",
+      "ea2413cd11bf1da93de9285381b471df", "c4f78ae2b994a3a999cb3f5dac2bb498",
+      "44804ec226453bc5f688506b56ad2a8a", "9de9c12a5f3bb8d4af13da8807dfe53f",
+      "c190dac15c08f2e591b222e1d75b60c2", "c46889b58b44d242e24b91ef531e9176",
+      "b6697e1256b60b3426a8980c7c6f9a80", "1e0eb156152fbb74b0cff41bdbdf98b5",
+      "98ab6c0abc45fd44565f84e66dc71133", "f2f2126fac1b7c0c7b7ff511c6f3c91e",
+      "0cc720e878cfa35f9b72762d08adb1bf", "6efee9ce87e098122dd05525f4c74a2f",
+      "187270514a93bd7065d2cfdb02146959", "947be7f2921b5a192d4296b2060a215c",
+      "42f02b046eda2a94133032184fdaa26d", "487e94b20867e7021dd1f10d477c3acf",
+      "9f9eac4394d8821f5c14857a28c5549b", "75d781b60c1f4aa44ceb6bc65f597a52",
+      "779f9ac3c01a86812964ccc38da2711a", "16dc8824efbd7a47808ccdbf8e37df56",
+      "e72899a8ddf6cc816e1917c25739a512", "96a4bcaedae79b55399d931fecd64312",
+      "5c5e8f4a4f0153315133e4e86a02c3a6", "d1c339b6f6cc0eabdd6674028e1f4260",
+      "4ef5868adaf6712d033dce9e51837c0b", "ed90a4ddfc463dddfe71314bc3415b4e",
+      "2312299492a47246269d6d37e67c8c0c", "56baf1c4453c5cf5ce3d6857cff4aa8f",
+      "d534ce3430377b355c3f59695cfb188b", "f40248f1a6fac4299c9645350138f598",
+      "f2e3cbbd066d9d28304667d82312d950", "e8a7784eb367b72b96486bec856b873c",
+      "02941ae2cf8272b353268a30cf9c2ee0", "8f6273a5fa62b9a4225ebdbf2ce44e27",
+      "85bb0aaba73fe8c89dcee6b5c55d5cfc", "c28c63a4e46ee2a98dd2b58379971c8c",
+      "4af35738c29d27ca9930a488bacdffe6", "34a419cc3e6ab21cf099d244169d253e",
+      "7c5b8d19ac8a81b37011fabac10143d0", "e582811e05def83270d8f65060fe8966",
+      "24662536326615a3c325409e780f65bf", "717a7f7e99d329a74391477ef3c6d738",
+      "e0f38a3dba4c6e060b6ca12a18d75fc2", "fbd0cba6a27eb06e74c5ed376187e05c",
+      "14dfb487c4a7e989629a195810b814ee", "3cf6d595317ec46e08f6eaa0f0e99b43",
+      "b3cb98c418ea854e433b612fc532bac5", "262206cee670c082361497e51cbd0f43",
+      "84c11b103a9b0a61f07493dcd269e6fd", "bd9bd9994057371252398bf52c7586f0",
+      "72e5537ba5f04fe17b7a371bd12ca0e2", "5986a20b406ceed273f9e41bc0c4c775",
+      "d5eb9ea00ce19079b49562ba4a8cb574", "3205e6f3c532a63f8d5d939fa46bc444",
+      "cfb21ac467f21954903948d4e6c9a2a1", "bd9fd6aab18bbba8096746f9ed35a640",
+      "d42ec4f13f042014c5b4af5f03d19034", "8a7fdee2b57ac641e03365625850f5d6",
+      "d18638521275b3aa9dd463d067d6a390", "a7a71c433d85576198b52608c99cab47",
+      "96e2a2443bf8cfe32d7590c5011c7523", "6fbe7cd83208937229c11a8e3be5e1e9",
+      "ecf66dac310e332a108be639171b5cf3", "327b1656c61d795c30a914f52e3d7629",
+      "157d26190bde1a6f34680708bff5d02e", "d927bba0073263a7914a4076a5edfe29",
+      "b88930ec68e5e49da8204ef21635cea2", "58e174ed0036b1ac1f5a9bdd44860222",
+      "415055dfa80c6fe7c12e4d16cac22168", "9058939bfb5998d6ecd71d87a52be893",
+      "847894efa35f1528732ec3584f62f86f", "8aa9b33c0d9695690cb4088c32f31214",
+      "11e28ab9a3192a2bc9ffd3fd0a466a13", "f246009c5efafd9310fa8e365d23cab4",
+      "2381fcd9ee0ffceba5509879d9f5709d", "1cf1dc7c7c6ecf1f3381455c99e2239e",
+      "e74601883b53791045f50bbcbbbcc803", "22926eecefa94f9f39b9bb9dbb183e5b",
+      "128c24f5a5342aebb21bdaa87907daf7", "11c39f844a2e51cc4c80ffe1afa58e70",
+      "2c0548cff2145031e304d8f97abfd751", "66e1a3daf84029341b999b18bf86e5b3",
+      "0f790f210d5366bbad7eb352b4909dd9",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct MaskBlendTestParam {
+  MaskBlendTestParam(BlockSize block_size, int subsampling_x, int subsampling_y,
+                     bool is_inter_intra, bool is_wedge_inter_intra)
+      : block_size(block_size),
+        width(kBlockWidthPixels[block_size]),
+        height(kBlockHeightPixels[block_size]),
+        subsampling_x(subsampling_x),
+        subsampling_y(subsampling_y),
+        is_inter_intra(is_inter_intra),
+        is_wedge_inter_intra(is_wedge_inter_intra) {}
+  BlockSize block_size;
+  int width;
+  int height;
+  int subsampling_x;
+  int subsampling_y;
+  bool is_inter_intra;
+  bool is_wedge_inter_intra;
+};
+
+std::ostream& operator<<(std::ostream& os, const MaskBlendTestParam& param) {
+  return os << ToString(param.block_size)
+            << ", subsampling(x/y): " << param.subsampling_x << "/"
+            << param.subsampling_y
+            << ", is_inter_intra: " << param.is_inter_intra
+            << ", is_wedge_inter_intra: " << param.is_wedge_inter_intra;
+}
+
+template <int bitdepth, typename Pixel>
+class MaskBlendTest : public testing::TestWithParam<MaskBlendTestParam>,
+                      public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  MaskBlendTest() = default;
+  ~MaskBlendTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    MaskBlendInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      MaskBlendInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        MaskBlendInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    func_ = (param_.is_inter_intra && !param_.is_wedge_inter_intra)
+                ? dsp->mask_blend[0][param_.is_inter_intra]
+                : dsp->mask_blend[param_.subsampling_x + param_.subsampling_y]
+                                 [param_.is_inter_intra];
+    func_8bpp_ = dsp->inter_intra_mask_blend_8bpp[param_.is_wedge_inter_intra
+                                                      ? param_.subsampling_x +
+                                                            param_.subsampling_y
+                                                      : 0];
+  }
+
+ protected:
+  int GetDigestIdOffset() const {
+    // id is for retrieving the corresponding digest from the lookup table given
+    // the set of input parameters. id can be figured out by the block size and
+    // an offset (id_offset).
+    // For example, in kMaskBlendTestParam, this set of parameters
+    // (8, 8, 0, 0, false, false) corresponds to the first entry in the
+    // digest lookup table, where id == 0.
+    // (8, 8, 1, 0, false, false) corresponds to id == 17.
+    // (8, 8, 1, 1, false, false) corresponds to id == 34.
+    // (8, 8, 0, 0, true, false) corresponds to id == 51.
+    // Id_offset denotes offset for different modes (is_inter_intra,
+    // is_wedge_inter_intra).
+    // ...
+    if (!param_.is_inter_intra && !param_.is_wedge_inter_intra) {
+      return param_.subsampling_x * 17 + param_.subsampling_y * 17;
+    }
+    if (param_.is_inter_intra && !param_.is_wedge_inter_intra) {
+      return 51 + param_.subsampling_x * 7 + param_.subsampling_y * 7;
+    }
+    if (param_.is_inter_intra && param_.is_wedge_inter_intra) {
+      return 72 + param_.subsampling_x * 7 + param_.subsampling_y * 7;
+    }
+    return 0;
+  }
+
+  int GetDigestId() const {
+    // Only 8x8 and larger blocks are tested.
+    int block_size_adjustment =
+        static_cast<int>(param_.block_size > kBlock16x4);
+    if (param_.is_inter_intra || param_.is_wedge_inter_intra) {
+      // 4:1/1:4 blocks are invalid for these modes.
+      block_size_adjustment += static_cast<int>(param_.block_size > kBlock8x32);
+      block_size_adjustment +=
+          static_cast<int>(param_.block_size > kBlock16x64);
+      block_size_adjustment += static_cast<int>(param_.block_size > kBlock32x8);
+      block_size_adjustment +=
+          static_cast<int>(param_.block_size > kBlock64x16);
+    }
+    return GetDigestIdOffset() + param_.block_size - kBlock8x8 -
+           block_size_adjustment;
+  }
+
+  void Test(const char* digest, int num_runs);
+
+ private:
+  using PredType =
+      typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
+  static constexpr int kStride = kMaxSuperBlockSizeInPixels;
+  static constexpr int kDestStride = kMaxSuperBlockSizeInPixels * sizeof(Pixel);
+  const MaskBlendTestParam param_ = GetParam();
+  alignas(kMaxAlignment) PredType
+      source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
+  uint8_t source1_8bpp_[kMaxSuperBlockSizeInPixels *
+                        kMaxSuperBlockSizeInPixels] = {};
+  alignas(kMaxAlignment) PredType
+      source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
+  uint8_t source2_8bpp_[kMaxSuperBlockSizeInPixels *
+                        kMaxSuperBlockSizeInPixels] = {};
+  uint8_t source2_8bpp_cache_[kMaxSuperBlockSizeInPixels *
+                              kMaxSuperBlockSizeInPixels] = {};
+  uint8_t mask_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
+  uint8_t dest_[sizeof(Pixel) * kMaxSuperBlockSizeInPixels *
+                kMaxSuperBlockSizeInPixels] = {};
+  dsp::MaskBlendFunc func_;
+  dsp::InterIntraMaskBlendFunc8bpp func_8bpp_;
+};
+
+template <int bitdepth, typename Pixel>
+void MaskBlendTest<bitdepth, Pixel>::Test(const char* const digest,
+                                          const int num_runs) {
+  if (func_ == nullptr && func_8bpp_ == nullptr) return;
+  const int width = param_.width >> param_.subsampling_x;
+  const int height = param_.height >> param_.subsampling_y;
+
+  // Add id offset to seed just to add more randomness to input blocks.
+  // If we use the same seed for different block sizes, the generated input
+  // blocks are repeated. For example, if input size is 8x8, the generated
+  // block is exactly the upper left half of the generated 16x16 block.
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed() +
+                             GetDigestIdOffset());
+  PredType* src_1 = source1_;
+  uint8_t* src_1_8bpp = source1_8bpp_;
+  PredType* src_2 = source2_;
+  uint8_t* src_2_8bpp = source2_8bpp_;
+  const ptrdiff_t src_2_stride = param_.is_inter_intra ? kStride : width;
+  const ptrdiff_t mask_stride = param_.width;
+  uint8_t* mask_row = mask_;
+  const int range_mask = (1 << (bitdepth)) - 1;
+  for (int y = 0; y < height; ++y) {
+    for (int x = 0; x < width; ++x) {
+      src_1[x] = static_cast<PredType>(rnd.Rand16() & range_mask);
+      src_2[x] = static_cast<PredType>(rnd.Rand16() & range_mask);
+      if (param_.is_inter_intra && bitdepth == 8) {
+        src_1_8bpp[x] = src_1[x];
+        src_2_8bpp[x] = src_2[x];
+      }
+      if (!param_.is_inter_intra) {
+        // Implies isCompound == true.
+        constexpr int bitdepth_index = (bitdepth - 8) >> 1;
+        const int min_val = kCompoundPredictionRange[bitdepth_index][0];
+        const int max_val = kCompoundPredictionRange[bitdepth_index][1];
+        src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+        src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
+      }
+    }
+    src_1 += width;
+    src_1_8bpp += width;
+    src_2 += src_2_stride;
+    src_2_8bpp += src_2_stride;
+  }
+  // Mask should be setup regardless of subsampling.
+  for (int y = 0; y < param_.height; ++y) {
+    for (int x = 0; x < param_.width; ++x) {
+      mask_row[x] = rnd.Rand8() & 63;
+      mask_row[x] += rnd.Rand8() & 1;  // Range of mask is [0, 64].
+    }
+    mask_row += mask_stride;
+  }
+
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_runs; ++i) {
+    const absl::Time start = absl::Now();
+    if (param_.is_inter_intra && bitdepth == 8) {
+      ASSERT_EQ(func_, nullptr);
+      static_assert(sizeof(source2_8bpp_cache_) == sizeof(source2_8bpp_), "");
+      // source2_8bpp_ is modified in the call.
+      memcpy(source2_8bpp_cache_, source2_8bpp_, sizeof(source2_8bpp_));
+      func_8bpp_(source1_8bpp_, source2_8bpp_, src_2_stride, mask_, mask_stride,
+                 width, height);
+      for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+          dest_[y * kDestStride + x] = source2_8bpp_[y * src_2_stride + x];
+        }
+      }
+      memcpy(source2_8bpp_, source2_8bpp_cache_, sizeof(source2_8bpp_));
+    } else {
+      if (bitdepth != 8) {
+        ASSERT_EQ(func_8bpp_, nullptr);
+      }
+      func_(source1_, source2_, src_2_stride, mask_, mask_stride, width, height,
+            dest_, kDestStride);
+    }
+    elapsed_time += absl::Now() - start;
+  }
+
+  test_utils::CheckMd5Digest("MaskBlend", ToString(param_.block_size), digest,
+                             dest_, sizeof(dest_), elapsed_time);
+}
+
+const MaskBlendTestParam kMaskBlendTestParam[] = {
+    // is_inter_intra = false, is_wedge_inter_intra = false.
+    // block size range is from 8x8 to 128x128.
+    MaskBlendTestParam(kBlock8x8, 0, 0, false, false),
+    MaskBlendTestParam(kBlock8x16, 0, 0, false, false),
+    MaskBlendTestParam(kBlock8x32, 0, 0, false, false),
+    MaskBlendTestParam(kBlock16x8, 0, 0, false, false),
+    MaskBlendTestParam(kBlock16x16, 0, 0, false, false),
+    MaskBlendTestParam(kBlock16x32, 0, 0, false, false),
+    MaskBlendTestParam(kBlock16x64, 0, 0, false, false),
+    MaskBlendTestParam(kBlock32x8, 0, 0, false, false),
+    MaskBlendTestParam(kBlock32x16, 0, 0, false, false),
+    MaskBlendTestParam(kBlock32x32, 0, 0, false, false),
+    MaskBlendTestParam(kBlock32x64, 0, 0, false, false),
+    MaskBlendTestParam(kBlock64x16, 0, 0, false, false),
+    MaskBlendTestParam(kBlock64x32, 0, 0, false, false),
+    MaskBlendTestParam(kBlock64x64, 0, 0, false, false),
+    MaskBlendTestParam(kBlock64x128, 0, 0, false, false),
+    MaskBlendTestParam(kBlock128x64, 0, 0, false, false),
+    MaskBlendTestParam(kBlock128x128, 0, 0, false, false),
+    MaskBlendTestParam(kBlock8x8, 1, 0, false, false),
+    MaskBlendTestParam(kBlock8x16, 1, 0, false, false),
+    MaskBlendTestParam(kBlock8x32, 1, 0, false, false),
+    MaskBlendTestParam(kBlock16x8, 1, 0, false, false),
+    MaskBlendTestParam(kBlock16x16, 1, 0, false, false),
+    MaskBlendTestParam(kBlock16x32, 1, 0, false, false),
+    MaskBlendTestParam(kBlock16x64, 1, 0, false, false),
+    MaskBlendTestParam(kBlock32x8, 1, 0, false, false),
+    MaskBlendTestParam(kBlock32x16, 1, 0, false, false),
+    MaskBlendTestParam(kBlock32x32, 1, 0, false, false),
+    MaskBlendTestParam(kBlock32x64, 1, 0, false, false),
+    MaskBlendTestParam(kBlock64x16, 1, 0, false, false),
+    MaskBlendTestParam(kBlock64x32, 1, 0, false, false),
+    MaskBlendTestParam(kBlock64x64, 1, 0, false, false),
+    MaskBlendTestParam(kBlock64x128, 1, 0, false, false),
+    MaskBlendTestParam(kBlock128x64, 1, 0, false, false),
+    MaskBlendTestParam(kBlock128x128, 1, 0, false, false),
+    MaskBlendTestParam(kBlock8x8, 1, 1, false, false),
+    MaskBlendTestParam(kBlock8x16, 1, 1, false, false),
+    MaskBlendTestParam(kBlock8x32, 1, 1, false, false),
+    MaskBlendTestParam(kBlock16x8, 1, 1, false, false),
+    MaskBlendTestParam(kBlock16x16, 1, 1, false, false),
+    MaskBlendTestParam(kBlock16x32, 1, 1, false, false),
+    MaskBlendTestParam(kBlock16x64, 1, 1, false, false),
+    MaskBlendTestParam(kBlock32x8, 1, 1, false, false),
+    MaskBlendTestParam(kBlock32x16, 1, 1, false, false),
+    MaskBlendTestParam(kBlock32x32, 1, 1, false, false),
+    MaskBlendTestParam(kBlock32x64, 1, 1, false, false),
+    MaskBlendTestParam(kBlock64x16, 1, 1, false, false),
+    MaskBlendTestParam(kBlock64x32, 1, 1, false, false),
+    MaskBlendTestParam(kBlock64x64, 1, 1, false, false),
+    MaskBlendTestParam(kBlock64x128, 1, 1, false, false),
+    MaskBlendTestParam(kBlock128x64, 1, 1, false, false),
+    MaskBlendTestParam(kBlock128x128, 1, 1, false, false),
+    // is_inter_intra = true, is_wedge_inter_intra = false.
+    // block size range is from 8x8 to 32x32 (no 4:1/1:4 blocks, Section 5.11.28
+    // Read inter intra syntax).
+    MaskBlendTestParam(kBlock8x8, 0, 0, true, false),
+    MaskBlendTestParam(kBlock8x16, 0, 0, true, false),
+    MaskBlendTestParam(kBlock16x8, 0, 0, true, false),
+    MaskBlendTestParam(kBlock16x16, 0, 0, true, false),
+    MaskBlendTestParam(kBlock16x32, 0, 0, true, false),
+    MaskBlendTestParam(kBlock32x16, 0, 0, true, false),
+    MaskBlendTestParam(kBlock32x32, 0, 0, true, false),
+    MaskBlendTestParam(kBlock8x8, 1, 0, true, false),
+    MaskBlendTestParam(kBlock8x16, 1, 0, true, false),
+    MaskBlendTestParam(kBlock16x8, 1, 0, true, false),
+    MaskBlendTestParam(kBlock16x16, 1, 0, true, false),
+    MaskBlendTestParam(kBlock16x32, 1, 0, true, false),
+    MaskBlendTestParam(kBlock32x16, 1, 0, true, false),
+    MaskBlendTestParam(kBlock32x32, 1, 0, true, false),
+    MaskBlendTestParam(kBlock8x8, 1, 1, true, false),
+    MaskBlendTestParam(kBlock8x16, 1, 1, true, false),
+    MaskBlendTestParam(kBlock16x8, 1, 1, true, false),
+    MaskBlendTestParam(kBlock16x16, 1, 1, true, false),
+    MaskBlendTestParam(kBlock16x32, 1, 1, true, false),
+    MaskBlendTestParam(kBlock32x16, 1, 1, true, false),
+    MaskBlendTestParam(kBlock32x32, 1, 1, true, false),
+    // is_inter_intra = true, is_wedge_inter_intra = true.
+    // block size range is from 8x8 to 32x32 (no 4:1/1:4 blocks, Section 5.11.28
+    // Read inter intra syntax).
+    MaskBlendTestParam(kBlock8x8, 0, 0, true, true),
+    MaskBlendTestParam(kBlock8x16, 0, 0, true, true),
+    MaskBlendTestParam(kBlock16x8, 0, 0, true, true),
+    MaskBlendTestParam(kBlock16x16, 0, 0, true, true),
+    MaskBlendTestParam(kBlock16x32, 0, 0, true, true),
+    MaskBlendTestParam(kBlock32x16, 0, 0, true, true),
+    MaskBlendTestParam(kBlock32x32, 0, 0, true, true),
+    MaskBlendTestParam(kBlock8x8, 1, 0, true, true),
+    MaskBlendTestParam(kBlock8x16, 1, 0, true, true),
+    MaskBlendTestParam(kBlock16x8, 1, 0, true, true),
+    MaskBlendTestParam(kBlock16x16, 1, 0, true, true),
+    MaskBlendTestParam(kBlock16x32, 1, 0, true, true),
+    MaskBlendTestParam(kBlock32x16, 1, 0, true, true),
+    MaskBlendTestParam(kBlock32x32, 1, 0, true, true),
+    MaskBlendTestParam(kBlock8x8, 1, 1, true, true),
+    MaskBlendTestParam(kBlock8x16, 1, 1, true, true),
+    MaskBlendTestParam(kBlock16x8, 1, 1, true, true),
+    MaskBlendTestParam(kBlock16x16, 1, 1, true, true),
+    MaskBlendTestParam(kBlock16x32, 1, 1, true, true),
+    MaskBlendTestParam(kBlock32x16, 1, 1, true, true),
+    MaskBlendTestParam(kBlock32x32, 1, 1, true, true),
+};
+
+using MaskBlendTest8bpp = MaskBlendTest<8, uint8_t>;
+
+TEST_P(MaskBlendTest8bpp, Blending) { Test(GetDigest8bpp(GetDigestId()), 1); }
+
+TEST_P(MaskBlendTest8bpp, DISABLED_Speed) {
+  Test(GetDigest8bpp(GetDigestId()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, MaskBlendTest8bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, MaskBlendTest8bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, MaskBlendTest8bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using MaskBlendTest10bpp = MaskBlendTest<10, uint16_t>;
+
+TEST_P(MaskBlendTest10bpp, Blending) { Test(GetDigest10bpp(GetDigestId()), 1); }
+
+TEST_P(MaskBlendTest10bpp, DISABLED_Speed) {
+  Test(GetDigest10bpp(GetDigestId()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, MaskBlendTest10bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, MaskBlendTest10bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, MaskBlendTest10bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using MaskBlendTest12bpp = MaskBlendTest<12, uint16_t>;
+
+TEST_P(MaskBlendTest12bpp, Blending) { Test(GetDigest12bpp(GetDigestId()), 1); }
+
+TEST_P(MaskBlendTest12bpp, DISABLED_Speed) {
+  Test(GetDigest12bpp(GetDigestId()), kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, MaskBlendTest12bpp,
+                         testing::ValuesIn(kMaskBlendTestParam));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/motion_field_projection_test.cc b/src/dsp/motion_field_projection_test.cc
new file mode 100644
index 0000000..3a47cc7
--- /dev/null
+++ b/src/dsp/motion_field_projection_test.cc
@@ -0,0 +1,213 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/motion_field_projection.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/reference_info.h"
+#include "src/utils/types.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kMotionFieldWidth = 160;
+constexpr int kMotionFieldHight = 120;
+
+// The 'int' parameter is unused but required to allow for instantiations of C,
+// NEON, etc.
+class MotionFieldProjectionTest : public testing::TestWithParam<int> {
+ public:
+  MotionFieldProjectionTest() = default;
+  MotionFieldProjectionTest(const MotionFieldProjectionTest&) = delete;
+  MotionFieldProjectionTest& operator=(const MotionFieldProjectionTest&) =
+      delete;
+  ~MotionFieldProjectionTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(8);
+    MotionFieldProjectionInit_C();
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      MotionFieldProjectionInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        MotionFieldProjectionInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    const Dsp* const dsp = GetDspTable(8);
+    ASSERT_NE(dsp, nullptr);
+    target_motion_field_projection_kernel_func_ =
+        dsp->motion_field_projection_kernel;
+  }
+
+  void SetInputData(int motion_field_width, libvpx_test::ACMRandom* rnd);
+  void TestRandomValues(bool speed);
+
+ private:
+  MotionFieldProjectionKernelFunc target_motion_field_projection_kernel_func_;
+  ReferenceInfo reference_info_;
+  TemporalMotionField motion_field_;
+};
+
+void MotionFieldProjectionTest::SetInputData(
+    const int motion_field_width, libvpx_test::ACMRandom* const rnd) {
+  ASSERT_TRUE(reference_info_.Reset(kMotionFieldHight, motion_field_width));
+  ASSERT_TRUE(motion_field_.mv.Reset(kMotionFieldHight, motion_field_width,
+                                     /*zero_initialize=*/false));
+  ASSERT_TRUE(motion_field_.reference_offset.Reset(kMotionFieldHight,
+                                                   motion_field_width,
+                                                   /*zero_initialize=*/false));
+  constexpr int order_hint_bits = 6;
+  unsigned int order_hint_shift_bits = Mod32(32 - order_hint_bits);
+  const unsigned int current_frame_order_hint =
+      rnd->Rand8() & ((1 << order_hint_bits) - 1);  // [0, 63]
+  uint8_t reference_frame_order_hint = 0;
+  reference_info_.relative_distance_to[0] = 0;
+  reference_info_.skip_references[kReferenceFrameIntra] = true;
+  reference_info_.projection_divisions[kReferenceFrameIntra] = 0;
+  for (int i = kReferenceFrameLast; i < kNumReferenceFrameTypes; ++i) {
+    reference_frame_order_hint =
+        rnd->Rand8() & ((1 << order_hint_bits) - 1);  // [0, 63]
+    const int relative_distance_to =
+        GetRelativeDistance(current_frame_order_hint,
+                            reference_frame_order_hint, order_hint_shift_bits);
+    reference_info_.relative_distance_to[i] = relative_distance_to;
+    reference_info_.skip_references[i] =
+        relative_distance_to > kMaxFrameDistance || relative_distance_to <= 0;
+    reference_info_.projection_divisions[i] =
+        reference_info_.skip_references[i]
+            ? 0
+            : kProjectionMvDivisionLookup[relative_distance_to];
+  }
+  for (int y = 0; y < kMotionFieldHight; ++y) {
+    for (int x = 0; x < motion_field_width; ++x) {
+      reference_info_.motion_field_reference_frame[y][x] =
+          static_cast<ReferenceFrameType>(rnd->Rand16() &
+                                          kReferenceFrameAlternate);
+      reference_info_.motion_field_mv[y][x].mv[0] = rnd->Rand16Signed() / 512;
+      reference_info_.motion_field_mv[y][x].mv[1] = rnd->Rand16Signed() / 512;
+    }
+  }
+  MotionVector invalid_mv;
+  invalid_mv.mv[0] = kInvalidMvValue;
+  invalid_mv.mv[1] = kInvalidMvValue;
+  MotionVector* const motion_field_mv = &motion_field_.mv[0][0];
+  int8_t* const motion_field_reference_offset =
+      &motion_field_.reference_offset[0][0];
+  std::fill(motion_field_mv, motion_field_mv + motion_field_.mv.size(),
+            invalid_mv);
+  std::fill(
+      motion_field_reference_offset,
+      motion_field_reference_offset + motion_field_.reference_offset.size(),
+      -128);
+}
+
+void MotionFieldProjectionTest::TestRandomValues(bool speed) {
+  static const char* const kDigestMv[8] = {
+      "87c2a74538f5c015809492ac2e521075", "ba7b4a5d82c6083b13a5b02eb7655ab7",
+      "8c37d96bf1744d5553860bf44a4f60a3", "720aa644f85e48995db9785e87cd02e3",
+      "9289c0c66524bb77a605870d78285f35", "f0326509885c2b2c89feeac53698cd47",
+      "6b9ad1d672dec825cb1803063d35badc", "dfe06c57cc9c70d27246df7fd0afa0b2"};
+  static const char* const kDigestReferenceOffset[8] = {
+      "d8d1384268d7cf5c4514b39c329f94fb", "7f30e79ceb064befbad64a20d206a540",
+      "61e2eb5644edbd3a91b939403edc891e", "7a018f1bf88193e86934241af445dc36",
+      "2d6166bf8bbe1db77baf687ecf71d028", "95fee61f0219e06076d6f0e1073b1a4e",
+      "64d0a63751267bdc573cab761f1fe685", "906a99e0e791dbcb9183c9b68ecc4ea3"};
+  const int num_tests = speed ? 2000 : 1;
+  if (target_motion_field_projection_kernel_func_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  for (int width_idx = 0; width_idx < 8; ++width_idx) {
+    const int motion_field_width = kMotionFieldWidth + width_idx;
+    SetInputData(motion_field_width, &rnd);
+    const int dst_sign = ((rnd.Rand16() & 1) != 0) ? 0 : -1;
+    const int reference_to_current_with_sign =
+        rnd.PseudoUniform(2 * kMaxFrameDistance + 1) - kMaxFrameDistance;
+    assert(std::abs(reference_to_current_with_sign) <= kMaxFrameDistance);
+    // Step of y8 and x8 is at least 16 except the last hop.
+    for (int step = 16; step <= 80; step += 16) {
+      const absl::Time start = absl::Now();
+      for (int k = 0; k < num_tests; ++k) {
+        for (int y8 = 0; y8 < kMotionFieldHight; y8 += step) {
+          const int y8_end = std::min(y8 + step, kMotionFieldHight);
+          for (int x8 = 0; x8 < motion_field_width; x8 += step) {
+            const int x8_end = std::min(x8 + step, motion_field_width);
+            target_motion_field_projection_kernel_func_(
+                reference_info_, reference_to_current_with_sign, dst_sign, y8,
+                y8_end, x8, x8_end, &motion_field_);
+          }
+        }
+      }
+      const absl::Duration elapsed_time = absl::Now() - start;
+      test_utils::CheckMd5Digest(
+          "MotionFieldProjectionKernel",
+          absl::StrFormat("(mv) width %d  step %d", motion_field_width, step)
+              .c_str(),
+          kDigestMv[width_idx], motion_field_.mv[0],
+          sizeof(motion_field_.mv[0][0]) * motion_field_.mv.size(),
+          elapsed_time);
+      test_utils::CheckMd5Digest(
+          "MotionFieldProjectionKernel",
+          absl::StrFormat("(ref offset) width %d  step %d", motion_field_width,
+                          step)
+              .c_str(),
+          kDigestReferenceOffset[width_idx], motion_field_.reference_offset[0],
+          sizeof(motion_field_.reference_offset[0][0]) *
+              motion_field_.reference_offset.size(),
+          elapsed_time);
+    }
+  }
+}
+
+TEST_P(MotionFieldProjectionTest, Correctness) { TestRandomValues(false); }
+
+TEST_P(MotionFieldProjectionTest, DISABLED_Speed) { TestRandomValues(true); }
+
+INSTANTIATE_TEST_SUITE_P(C, MotionFieldProjectionTest, testing::Values(0));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, MotionFieldProjectionTest, testing::Values(0));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, MotionFieldProjectionTest, testing::Values(0));
+#endif
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/motion_vector_search_test.cc b/src/dsp/motion_vector_search_test.cc
new file mode 100644
index 0000000..a7b2ec8
--- /dev/null
+++ b/src/dsp/motion_vector_search_test.cc
@@ -0,0 +1,197 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/motion_vector_search.h"
+
+#include <cstdint>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "src/utils/types.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// The 'int' parameter is unused but required to allow for instantiations of C,
+// NEON, etc.
+class MotionVectorSearchTest : public testing::TestWithParam<int>,
+                               public test_utils::MaxAlignedAllocable {
+ public:
+  MotionVectorSearchTest() = default;
+  MotionVectorSearchTest(const MotionVectorSearchTest&) = delete;
+  MotionVectorSearchTest& operator=(const MotionVectorSearchTest&) = delete;
+  ~MotionVectorSearchTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(8);
+    MotionVectorSearchInit_C();
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      MotionVectorSearchInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        MotionVectorSearchInit_SSE4_1();
+      }
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    const Dsp* const dsp = GetDspTable(8);
+    ASSERT_NE(dsp, nullptr);
+    mv_projection_compound_[0] = dsp->mv_projection_compound[0];
+    mv_projection_compound_[1] = dsp->mv_projection_compound[1];
+    mv_projection_compound_[2] = dsp->mv_projection_compound[2];
+    mv_projection_single_[0] = dsp->mv_projection_single[0];
+    mv_projection_single_[1] = dsp->mv_projection_single[1];
+    mv_projection_single_[2] = dsp->mv_projection_single[2];
+  }
+
+  void SetInputData(libvpx_test::ACMRandom* rnd);
+  void TestRandomValues(bool speed);
+
+ private:
+  MvProjectionCompoundFunc mv_projection_compound_[3];
+  MvProjectionSingleFunc mv_projection_single_[3];
+  int reference_offsets_[2];
+  alignas(kMaxAlignment)
+      MotionVector temporal_mvs_[kMaxTemporalMvCandidatesWithPadding];
+  int8_t temporal_reference_offsets_[kMaxTemporalMvCandidatesWithPadding];
+  CompoundMotionVector compound_mv_org_[kMaxTemporalMvCandidates + 1]
+                                       [kMaxTemporalMvCandidatesWithPadding];
+  alignas(kMaxAlignment)
+      CompoundMotionVector compound_mv_[kMaxTemporalMvCandidates + 1]
+                                       [kMaxTemporalMvCandidatesWithPadding];
+  MotionVector single_mv_org_[kMaxTemporalMvCandidates + 1]
+                             [kMaxTemporalMvCandidatesWithPadding];
+  alignas(kMaxAlignment)
+      MotionVector single_mv_[kMaxTemporalMvCandidates + 1]
+                             [kMaxTemporalMvCandidatesWithPadding];
+};
+
+void MotionVectorSearchTest::SetInputData(libvpx_test::ACMRandom* const rnd) {
+  reference_offsets_[0] =
+      Clip3(rnd->Rand16(), -kMaxFrameDistance, kMaxFrameDistance);
+  reference_offsets_[1] =
+      Clip3(rnd->Rand16(), -kMaxFrameDistance, kMaxFrameDistance);
+  for (int i = 0; i < kMaxTemporalMvCandidatesWithPadding; ++i) {
+    temporal_reference_offsets_[i] = rnd->RandRange(kMaxFrameDistance);
+    for (auto& mv : temporal_mvs_[i].mv) {
+      mv = rnd->Rand16Signed() / 8;
+    }
+  }
+  for (int i = 0; i <= kMaxTemporalMvCandidates; ++i) {
+    for (int j = 0; j < kMaxTemporalMvCandidatesWithPadding; ++j) {
+      for (int k = 0; k < 2; ++k) {
+        single_mv_[i][j].mv[k] = rnd->Rand16Signed();
+        for (auto& mv : compound_mv_[i][j].mv[k].mv) {
+          mv = rnd->Rand16Signed();
+        }
+      }
+      compound_mv_org_[i][j] = compound_mv_[i][j];
+      single_mv_org_[i][j] = single_mv_[i][j];
+    }
+  }
+}
+
+void MotionVectorSearchTest::TestRandomValues(bool speed) {
+  static const char* const kDigestCompound[3] = {
+      "74c055b06c3701b2e50f2c964a6130b9", "cab21dd54f0a1bf6e80b58cdcf1fe0a9",
+      "e42de30cd84fa4e7b8581a330ed08a8b"};
+  static const char* const kDigestSingle[3] = {
+      "265ffbb59d0895183f8e2d90b6652c71", "5068d980c4ce42ed3f11963b8aece6cc",
+      "7e699d58df3954a38ff11c8e34151e66"};
+  const int num_tests = speed ? 1000000 : 1;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  for (int function_index = 0; function_index < 3; ++function_index) {
+    SetInputData(&rnd);
+    if (mv_projection_compound_[function_index] == nullptr) continue;
+    const absl::Time start = absl::Now();
+    for (int count = 1; count <= kMaxTemporalMvCandidates; ++count) {
+      const int total_count = count + (count & 1);
+      for (int i = 0; i < num_tests; ++i) {
+        mv_projection_compound_[function_index](
+            temporal_mvs_, temporal_reference_offsets_, reference_offsets_,
+            count, compound_mv_[count]);
+      }
+      // One more element could be calculated in SIMD implementations.
+      // Restore the original values if any.
+      for (int i = count; i < total_count; ++i) {
+        compound_mv_[count][i] = compound_mv_org_[count][i];
+      }
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    test_utils::CheckMd5Digest(
+        "MvProjectionCompound",
+        absl::StrFormat("function_index %d", function_index).c_str(),
+        kDigestCompound[function_index], compound_mv_, sizeof(compound_mv_),
+        elapsed_time);
+  }
+  for (int function_index = 0; function_index < 3; ++function_index) {
+    SetInputData(&rnd);
+    if (mv_projection_single_[function_index] == nullptr) continue;
+    const absl::Time start = absl::Now();
+    for (int count = 1; count <= kMaxTemporalMvCandidates; ++count) {
+      const int total_count = (count + 3) & ~3;
+      for (int i = 0; i < num_tests; ++i) {
+        mv_projection_single_[function_index](
+            temporal_mvs_, temporal_reference_offsets_, reference_offsets_[0],
+            count, single_mv_[count]);
+      }
+      // Up to three more elements could be calculated in SIMD implementations.
+      // Restore the original values if any.
+      for (int i = count; i < total_count; ++i) {
+        single_mv_[count][i] = single_mv_org_[count][i];
+      }
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    test_utils::CheckMd5Digest(
+        "MvProjectionSingle",
+        absl::StrFormat("function_index %d", function_index).c_str(),
+        kDigestSingle[function_index], single_mv_, sizeof(single_mv_),
+        elapsed_time);
+  }
+}
+
+TEST_P(MotionVectorSearchTest, Correctness) { TestRandomValues(false); }
+
+TEST_P(MotionVectorSearchTest, DISABLED_Speed) { TestRandomValues(true); }
+
+INSTANTIATE_TEST_SUITE_P(C, MotionVectorSearchTest, testing::Values(0));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, MotionVectorSearchTest, testing::Values(0));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, MotionVectorSearchTest, testing::Values(0));
+#endif
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/obmc_test.cc b/src/dsp/obmc_test.cc
new file mode 100644
index 0000000..a10feb2
--- /dev/null
+++ b/src/dsp/obmc_test.cc
@@ -0,0 +1,415 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/obmc.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ostream>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+#include "src/dsp/obmc.inc"
+
+constexpr int kMaxBlendingBlockSize = 64;
+constexpr int kNumSpeedTests = 2e8;
+
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigest[] = {
+      "c8659acd1e8ecdab06be73f0954fa1ae", "e785f31f2723a193fefd534bd6f6c18f",
+      "751fcd8a345fef1c38a25293c9b528c0", "69af412dfa5e96ad43b79c178cb1c58b",
+      "2766a64622e183bb4614f2018f14fa85", "8d98589a5cef6e68ee8fadf19d420e3c",
+      "19eccf31dd8cf1abcee9414128fe4141", "35019f98e30bcbc6ab624682a0628519",
+      "199c551164e73c100045d7ab033ffdcc", "ad5a5eb2906265690c22741b0715f37b",
+      "e2152dea159249149ff4151111b73ed6", "1edd570bec7e63780d83588f6aacda25",
+      "b24ad192e151b1e0f74d1493004cb1b6", "6c1ce7ed3463cc60870e336f990d4f14",
+      "2e6b7a06da21512dfdd9a517d2988655", "971ba1c41ab13bb341c04f936760f546",
+      "55b803239d9f12888c666c5320450937", "3d0838963f8c95dafbfb8e5e25c865d2",
+      "98a9be6245720d4e0da18115c1a1dbd7", "7e7afe3136ad681b5ea05664fe916548",
+      "33971753243f09106173199b7bae1ef5", "65413f33c19a42c112d395121aa4b3b4",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetDigestSpeed8bpp(int id) {
+  static const char* const kDigest[] = {
+      "5ea519b616cd2998fbb9b25b4c2660cb", "f23d18197a96de48901738d130a147d9",
+      "07b4140c693947a63865f835089766c4", "62547d29bc4dfb2e201e9d907c09e345",
+      "c3988da521be50aeb9944564001b282b", "d5a8ff9ca1bd49f4260bb497c489b06c",
+      "b3e94f1e33c316759ebf47620327168c", "c5e64a34ca7e55f4daed19cbe4c27049",
+      "3b234eb729e8e79db8692c4cbe1b6667", "f9f3060a44c3a575470f9700b3c3a75b",
+      "e3a1960b0a7238db1184a3f9d8e9a4b2", "ba9938553703d520bc0ade427c397140",
+      "31bf64a6ed1e8002d488c0b9dcffb80a", "9ab1f3ae2e7f70cd27452f30cecfd18e",
+      "eaf25ac79ad70fc17ca96d8fcdf0f939", "9aaa88cb5e6b8757e37c3430bd664e70",
+      "8293874b2794df8fd22f5a35c3de7bee", "e9d6ee9106227c2c67ea9e6a4652e4ad",
+      "29f8a6fc2a650f3945a4ea6d3b975b6d", "8f300a257e913a42666b4921b2b0b5c5",
+      "a526265c4b3c8593736a82ddc1fd1603", "76e248f6756ac96343204b0e48d72a9e",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigest[] = {
+      "6f922e4142b644ca3f1eb0f363a1c34e", "84e7c098a9335b36082fec0bc7203075",
+      "40f00ea6884fea23a3b7fae59e3b02c3", "70cb92d08b4fdb6dd9c7d418cb1455d3",
+      "ed550798b56e70439a93cb48c359e873", "55e0d927b984e78cd51a1961e58a431d",
+      "482a6856b87265a82e4ea3fdadb2d95b", "0be46226ff87d74ff2ce68a83eaf9cca",
+      "bb4461f0131a1693a0a76f21d92a480b", "ea24f78d74c7864fb247c9a98c9b97b6",
+      "d2e70b81882aeb3d9fccef89e7552a9d", "f5d882ee6d9ae6f7dfa467ca99301424",
+      "824ddb98eb4129b3d254c0bc7a64cd73", "5eaaafa8ef9b7ba5e2856a947e5b33df",
+      "071de1494e0f1b2f99266b90bdc43ddd", "c33227a96dad506adc32dacfb371ab78",
+      "e8a632f9fff240c439d4ae6e86795046", "26b90d74f18f9df4427b6180d48db1fc",
+      "e4a01e492ddc0398b5c5b60c81468242", "f1b4f7ab5c8b949e51db104f2e33565a",
+      "b1fb9ecc6a552e2b23ee92e2f3e4122a", "a683d20129a91bb20b904aa20c0499b1",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetDigestSpeed10bpp(int id) {
+  static const char* const kDigest[] = {
+      "80557576299708005111029cef04da53", "24f84f07f53f61cd46bdcfe1e05ff9b5",
+      "4dd6bc62145baa5357a4cbf6d7a6ef15", "0b7aa27cee43b8ae0c02d07887eaa225",
+      "9e28cdae73ca97433499c31ca79e1d07", "1cacd6466a143f88e736fffaf21e2246",
+      "9c7699626660d8965e06a54282a408f3", "eef893efef62b2eb4aaad06fc462819c",
+      "4965d0a3ff750813df85c0082b21bd4b", "ec10fd79fbf552abc595def392e9a863",
+      "a148bbafdc4466fbb700b31acccca8ac", "5da9d960988549f53b817003b93e4d01",
+      "b4c4f88d1fb54869ce7ff452ca7786a6", "d607f785fce62bad85102054539e7089",
+      "b441761ea2817e4618c594aaa11d670a", "1cc5e08e6d5f9315dbc0369b97af941d",
+      "568cc1a3a67ba4e6e77f54602d0ed3e3", "522f14c068f788bc284a7d1e47d623ed",
+      "b543855cbe384b88861c881853c28192", "5faaafc124e94eedc69dc0f5d33dacac",
+      "13ca4d01bd20085459e6126555e1f7b5", "46d46fae3c8a7d9e4725154d8d2b76d8",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigest[] = {
+      "eb18c776d7b56280f01cca40b04a9c44", "058d4a6ed025eac5dcf7aec3203c0882",
+      "8355884d7470e9c6af9309ab23bee859", "2ba330551ac58d1d034b947d7ab9b59f",
+      "0d25cd773c81e4c57f82513e3b031f01", "b9075f7c3b9a240dbb015a24454eeb71",
+      "563ed8683723d1e4f2746280bca3db0a", "d7125306bd8c952d0f85fe1515ca16a7",
+      "5bf99c7e4a918c9b6a7e251484ea6527", "38ac9c685e8d2bd2771b6f2b38268301",
+      "abc39dbde7470e08b15417ee97c704b2", "37e12753d23b7a8df92b1d32f3170d9f",
+      "9a609776cfa31f64826225d0a6b7afdd", "ccdd89e70e94f751fd891b124c1c3210",
+      "2bbf7b095e26ed4f27e7d05e20117084", "9a1b403c3a7c00da5686bcb87f1270e8",
+      "701d651e391043ab8ebbd0023a430980", "0047f10bdd8321494e8e82597fe2f969",
+      "f97e662d139b2811e3d3227de95135a2", "852933b90d4a70f9254157381ed641e0",
+      "cfcda707ec8e4361ef741dc716888348", "95e34eab83b3159f61685db248c6a881",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+
+const char* GetDigestSpeed12bpp(int id) {
+  static const char* const kDigest[] = {
+      "6c0f37c41d72ce40d95545ac0f08d88a", "8a8efeb7d8b2f852d76d0176b6c6878f",
+      "5757c88d1cdc0cd29c47c346474161f0", "fef8cf06d16ba7357bfc061e43080cd3",
+      "6bd11582448532bce8b91cc8807ab6a0", "1e6dd42eada2d636e210f4e20a771102",
+      "377a0472f45fcb42f1712243ea845530", "e3760f2b6e69c1b40e71ecde711d227c",
+      "6721638d1a5dadb96ddd0ca067c737ca", "3d3a23210a8496a76991bcec5045808b",
+      "2cbd26ecf7d4e927ab569083d3ddb4ca", "7d61af2d7841d1a39a2e930bac166804",
+      "dd929506442fb1f2e67130fe8cdf487b", "c0e57f8d2546d5bcb646a24d09d83d7c",
+      "2989c6487456c92eb003c8e17e904f45", "5cfb60a3be6ee5c41e0f655a3020f687",
+      "28f37d47cb07aa382659ff556a55a4c6", "b6478ab317b11f592deb60d02ce62f2f",
+      "bc78e7250c101f82e794d4fa0ee55025", "24304ed23d336a46f205206d3c5d48ef",
+      "dc1e71d95d06c1086bb7f9e05e38bf39", "32606ef72985e7de608df2e8760784b7",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct ObmcTestParam {
+  ObmcTestParam(int width, int height, ObmcDirection blending_direction)
+      : width(width), height(height), blending_direction(blending_direction) {}
+  int width;
+  int height;
+  ObmcDirection blending_direction;
+};
+
+std::ostream& operator<<(std::ostream& os, const ObmcTestParam& param) {
+  return os << "BlockSize" << param.width << "x" << param.height
+            << ", blending_direction: " << ToString(param.blending_direction);
+}
+
+template <int bitdepth, typename Pixel>
+class ObmcBlendTest : public testing::TestWithParam<ObmcTestParam> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  ObmcBlendTest() = default;
+  ~ObmcBlendTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    ObmcInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      if ((GetCpuInfo() & kSSE4_1) != 0) {
+        ObmcInit_SSE4_1();
+      }
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      ObmcInit_NEON();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    func_ = dsp->obmc_blend[blending_direction_];
+  }
+
+ protected:
+  int GetDigestId() const {
+    // blending_direction_ == kObmcDirectionVertical:
+    // (width, height):
+    // (4, 2), id = 0. (4, 4), id = 1. (4, 8), id = 2. (8, 4), id = 3.
+    // ...
+    // blending_direction_ == kObmcDirectionHorizontal: id starts from 11.
+    // Vertical skips (2, 4) while horizontal skips (4, 2) creating a gap after
+    // (2, 4).
+    const int id = (blending_direction_ == kObmcDirectionVertical) ? 0
+                   : (width_ == 2)                                 ? 12
+                                                                   : 11;
+    if (width_ == height_) return id + 3 * (FloorLog2(width_) - 1) - 2;
+    if (width_ < height_) return id + 3 * (FloorLog2(width_) - 1) - 1;
+    return id + 3 * (FloorLog2(height_) - 1);
+  }
+
+  // Note |digest| is only used when |use_fixed_values| is false.
+  void Test(const char* digest, bool use_fixed_values, int value);
+  void TestSpeed(const char* digest, int num_runs);
+
+ private:
+  const int width_ = GetParam().width;
+  const int height_ = GetParam().height;
+  const ObmcDirection blending_direction_ = GetParam().blending_direction;
+  Pixel source1_[kMaxBlendingBlockSize * kMaxBlendingBlockSize] = {};
+  Pixel source2_[kMaxBlendingBlockSize * kMaxBlendingBlockSize] = {};
+  dsp::ObmcBlendFunc func_;
+};
+
+template <int bitdepth, typename Pixel>
+void ObmcBlendTest<bitdepth, Pixel>::Test(const char* const digest,
+                                          const bool use_fixed_values,
+                                          const int value) {
+  if (func_ == nullptr) return;
+  if (use_fixed_values) {
+    std::fill(source1_,
+              source1_ + kMaxBlendingBlockSize * kMaxBlendingBlockSize, value);
+    std::fill(source2_,
+              source2_ + kMaxBlendingBlockSize * kMaxBlendingBlockSize, value);
+  } else {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    Pixel* src_1 = source1_;
+    Pixel* src_2 = source2_;
+    const int mask = (1 << bitdepth) - 1;
+    for (int y = 0; y < height_; ++y) {
+      for (int x = 0; x < width_; ++x) {
+        src_1[x] = rnd.Rand16() & mask;
+        src_2[x] = rnd.Rand16() & mask;
+      }
+      src_1 += kMaxBlendingBlockSize;
+      src_2 += width_;
+    }
+  }
+  const ptrdiff_t stride = kMaxBlendingBlockSize * sizeof(Pixel);
+  func_(source1_, stride, width_, height_, source2_,
+        width_ * sizeof(source2_[0]));
+  if (use_fixed_values) {
+    const bool success = test_utils::CompareBlocks(
+        source1_, source2_, width_, height_, kMaxBlendingBlockSize,
+        kMaxBlendingBlockSize, false);
+    EXPECT_TRUE(success);
+  } else {
+    test_utils::CheckMd5Digest(
+        ToString(blending_direction_),
+        absl::StrFormat("%dx%d", width_, height_).c_str(), digest, source1_,
+        sizeof(source1_), absl::Duration());
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void ObmcBlendTest<bitdepth, Pixel>::TestSpeed(const char* const digest,
+                                               const int num_runs) {
+  if (func_ == nullptr) return;
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  Pixel* src_1 = source1_;
+  Pixel* src_2 = source2_;
+  const int mask = (1 << bitdepth) - 1;
+  for (int y = 0; y < height_; ++y) {
+    for (int x = 0; x < width_; ++x) {
+      src_1[x] = rnd.Rand16() & mask;
+      src_2[x] = rnd.Rand16() & mask;
+    }
+    src_1 += kMaxBlendingBlockSize;
+    src_2 += width_;
+  }
+  const ptrdiff_t stride = kMaxBlendingBlockSize * sizeof(Pixel);
+  uint8_t dest[sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize];
+  absl::Duration elapsed_time;
+  for (int i = 0; i < num_runs; ++i) {
+    memcpy(dest, source1_,
+           sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize);
+    const absl::Time start = absl::Now();
+    func_(dest, stride, width_, height_, source2_,
+          width_ * sizeof(source2_[0]));
+    elapsed_time += absl::Now() - start;
+  }
+  memcpy(source1_, dest,
+         sizeof(Pixel) * kMaxBlendingBlockSize * kMaxBlendingBlockSize);
+  test_utils::CheckMd5Digest(ToString(blending_direction_),
+                             absl::StrFormat("%dx%d", width_, height_).c_str(),
+                             digest, source1_, sizeof(source1_), elapsed_time);
+}
+
+const ObmcTestParam kObmcTestParam[] = {
+    ObmcTestParam(4, 2, kObmcDirectionVertical),
+    ObmcTestParam(4, 4, kObmcDirectionVertical),
+    ObmcTestParam(4, 8, kObmcDirectionVertical),
+    ObmcTestParam(8, 4, kObmcDirectionVertical),
+    ObmcTestParam(8, 8, kObmcDirectionVertical),
+    ObmcTestParam(8, 16, kObmcDirectionVertical),
+    ObmcTestParam(16, 8, kObmcDirectionVertical),
+    ObmcTestParam(16, 16, kObmcDirectionVertical),
+    ObmcTestParam(16, 32, kObmcDirectionVertical),
+    ObmcTestParam(32, 16, kObmcDirectionVertical),
+    ObmcTestParam(32, 32, kObmcDirectionVertical),
+    ObmcTestParam(2, 4, kObmcDirectionHorizontal),
+    ObmcTestParam(4, 4, kObmcDirectionHorizontal),
+    ObmcTestParam(4, 8, kObmcDirectionHorizontal),
+    ObmcTestParam(8, 4, kObmcDirectionHorizontal),
+    ObmcTestParam(8, 8, kObmcDirectionHorizontal),
+    ObmcTestParam(8, 16, kObmcDirectionHorizontal),
+    ObmcTestParam(16, 8, kObmcDirectionHorizontal),
+    ObmcTestParam(16, 16, kObmcDirectionHorizontal),
+    ObmcTestParam(16, 32, kObmcDirectionHorizontal),
+    ObmcTestParam(32, 16, kObmcDirectionHorizontal),
+    ObmcTestParam(32, 32, kObmcDirectionHorizontal),
+};
+
+using ObmcBlendTest8bpp = ObmcBlendTest<8, uint8_t>;
+
+TEST_P(ObmcBlendTest8bpp, Blending) {
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 255);
+  Test(GetDigest8bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
+}
+
+TEST_P(ObmcBlendTest8bpp, DISABLED_Speed) {
+  TestSpeed(GetDigestSpeed8bpp(GetDigestId()),
+            kNumSpeedTests / (GetParam().height * GetParam().width));
+}
+
+INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest8bpp,
+                         testing::ValuesIn(kObmcTestParam));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, ObmcBlendTest8bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ObmcBlendTest8bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using ObmcBlendTest10bpp = ObmcBlendTest<10, uint16_t>;
+
+TEST_P(ObmcBlendTest10bpp, Blending) {
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, (1 << 10) - 1);
+  Test(GetDigest10bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
+}
+
+TEST_P(ObmcBlendTest10bpp, DISABLED_Speed) {
+  TestSpeed(GetDigestSpeed10bpp(GetDigestId()),
+            kNumSpeedTests / (GetParam().height * GetParam().width));
+}
+
+INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest10bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, ObmcBlendTest10bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#endif
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ObmcBlendTest10bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using ObmcBlendTest12bpp = ObmcBlendTest<12, uint16_t>;
+
+TEST_P(ObmcBlendTest12bpp, Blending) {
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 0);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 1);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, 128);
+  Test(/*digest=*/nullptr, /*use_fixed_values=*/true, (1 << 12) - 1);
+  Test(GetDigest12bpp(GetDigestId()), /*use_fixed_values=*/false, -1);
+}
+
+TEST_P(ObmcBlendTest12bpp, DISABLED_Speed) {
+  TestSpeed(GetDigestSpeed12bpp(GetDigestId()),
+            kNumSpeedTests / (GetParam().height * GetParam().width));
+}
+
+INSTANTIATE_TEST_SUITE_P(C, ObmcBlendTest12bpp,
+                         testing::ValuesIn(kObmcTestParam));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/super_res_test.cc b/src/dsp/super_res_test.cc
new file mode 100644
index 0000000..7b253ff
--- /dev/null
+++ b/src/dsp/super_res_test.cc
@@ -0,0 +1,302 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/super_res.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kNumSpeedTests = 5e5;
+
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigestSuperRes[] = {
+      "52eb4eac1df0c51599d57696405b69d0", "ccb07cc8295fd1440ff2e3b9199ec4f9",
+      "baef34cca795b95f3d1fd81d609da679", "03f1579c2773c8ba9c867316a22b94a3"};
+  return kDigestSuperRes[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigestSuperRes[] = {
+      "8fd78e05d944aeb11fac278b47ee60ba", "948eaecb70fa5614ce1c1c95e9942dc3",
+      "126cd7727e787e0625ec3f5ce97f8fa0", "85c806c41d40b841764bcb54f6d3a712"};
+  return kDigestSuperRes[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigestSuperRes[] = {
+      "9a08983d82df4983700976f18919201b", "6e5edbafcb6c38db37258bf79c00ea32",
+      "f5c57e6d3b518f9585f768ed19b91568", "b5de9b93c8a1a50580e7c7c9456fb615"};
+  return kDigestSuperRes[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct SuperResTestParam {
+  SuperResTestParam(int downscaled_width, int upscaled_width)
+      : downscaled_width(downscaled_width), upscaled_width(upscaled_width) {}
+  int downscaled_width;
+  int upscaled_width;
+};
+
+template <int bitdepth, typename Pixel, typename Coefficient>
+class SuperResTest : public testing::TestWithParam<SuperResTestParam>,
+                     public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  SuperResTest() = default;
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    SuperResInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const std::vector<std::string> split_test_name =
+        absl::StrSplit(test_info->name(), '/');
+    ASSERT_TRUE(absl::SimpleAtoi(split_test_name[1], &test_id_));
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      SuperResInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      SuperResInit_SSE4_1();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    super_res_coefficients_ = dsp->super_res_coefficients;
+    func_ = dsp->super_res;
+  }
+
+  void TestComputeSuperRes(int fixed_value, int num_runs);
+
+ private:
+  static constexpr int kHeight = 127;
+  // The maximum width that must be allocated.
+  static constexpr int kUpscaledBufferWidth = 192;
+  // Allow room for the filter taps.
+  static constexpr int kStride =
+      ((kUpscaledBufferWidth + 2 * kSuperResHorizontalBorder + 15) & ~15);
+  const int kDownscaledWidth = GetParam().downscaled_width;
+  const int kUpscaledWidth = GetParam().upscaled_width;
+  int test_id_;
+  SuperResCoefficientsFunc super_res_coefficients_;
+  SuperResFunc func_;
+  Pixel source_buffer_[kHeight][kStride];
+  alignas(kMaxAlignment) Pixel dest_buffer_[kHeight][kStride];
+  alignas(kMaxAlignment) Coefficient
+      superres_coefficients_[kSuperResFilterTaps * kUpscaledBufferWidth];
+};
+
+template <int bitdepth, typename Pixel, typename Coefficient>
+void SuperResTest<bitdepth, Pixel, Coefficient>::TestComputeSuperRes(
+    int fixed_value, int num_runs) {
+  if (func_ == nullptr) return;
+  const int superres_width = kDownscaledWidth << kSuperResScaleBits;
+  const int step = (superres_width + kUpscaledWidth / 2) / kUpscaledWidth;
+  const int error = step * kUpscaledWidth - superres_width;
+  const int initial_subpixel_x =
+      ((-((kUpscaledWidth - kDownscaledWidth) << (kSuperResScaleBits - 1)) +
+        DivideBy2(kUpscaledWidth)) /
+           kUpscaledWidth +
+       (1 << (kSuperResExtraBits - 1)) - error / 2) &
+      kSuperResScaleMask;
+  if (super_res_coefficients_ != nullptr) {
+    super_res_coefficients_(kUpscaledWidth, initial_subpixel_x, step,
+                            superres_coefficients_);
+  }
+  memset(dest_buffer_, 0, sizeof(dest_buffer_));
+  if (fixed_value != 0) {
+    SetBlock<Pixel>(kHeight, kStride, fixed_value, source_buffer_[0], kStride);
+  } else {
+    // Random values.
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    const int bitdepth_mask = (1 << bitdepth) - 1;
+    for (int y = 0; y < kHeight; ++y) {
+      for (int x = 0; x < kStride; ++x) {
+        source_buffer_[y][x] = rnd.Rand16() & bitdepth_mask;
+      }
+    }
+  }
+  // Offset starting point in the buffer to accommodate line extension.
+  Pixel* src_ptr = source_buffer_[0] + kSuperResHorizontalBorder;
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    func_(superres_coefficients_, src_ptr, kStride, kHeight, kDownscaledWidth,
+          kUpscaledWidth, initial_subpixel_x, step, dest_buffer_, kStride);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+
+  if (fixed_value != 0) {
+    for (int y = 0; y < kHeight; ++y) {
+      for (int x = 0; x < kUpscaledWidth; ++x) {
+        EXPECT_TRUE(dest_buffer_[y][x] == fixed_value)
+            << "At location [" << y << ", " << x
+            << "]\nexpected: " << fixed_value
+            << "\nactual: " << dest_buffer_[y][x];
+      }
+    }
+  } else if (num_runs == 1) {
+    // Random values.
+    if ((kUpscaledWidth & 15) != 0) {
+      // The SIMD functions overwrite up to 15 pixels in each row. Reset them.
+      for (int y = 0; y < kHeight; ++y) {
+        for (int x = kUpscaledWidth; x < Align(kUpscaledWidth, 16); ++x) {
+          dest_buffer_[y][x] = 0;
+        }
+      }
+    }
+    const char* expected_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        expected_digest = GetDigest8bpp(test_id_);
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        expected_digest = GetDigest10bpp(test_id_);
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        expected_digest = GetDigest12bpp(test_id_);
+        break;
+#endif
+    }
+    ASSERT_NE(expected_digest, nullptr);
+    test_utils::CheckMd5Digest(
+        "SuperRes",
+        absl::StrFormat("width %d, step %d, start %d", kUpscaledWidth, step,
+                        initial_subpixel_x)
+            .c_str(),
+        expected_digest, dest_buffer_, sizeof(dest_buffer_), elapsed_time);
+  } else {
+    // Speed test.
+    printf("Mode SuperRes [width %d, step %d, start %d]: %d us\n",
+           kUpscaledWidth, step, initial_subpixel_x,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+}
+
+using SuperResTest8bpp = SuperResTest<8, uint8_t, int8_t>;
+
+TEST_P(SuperResTest8bpp, FixedValues) {
+  TestComputeSuperRes(100, 1);
+  TestComputeSuperRes(255, 1);
+  TestComputeSuperRes(1, 1);
+}
+
+TEST_P(SuperResTest8bpp, RandomValues) { TestComputeSuperRes(0, 1); }
+
+TEST_P(SuperResTest8bpp, DISABLED_Speed) {
+  TestComputeSuperRes(0, kNumSpeedTests);
+}
+
+const SuperResTestParam kSuperResTestParams[] = {
+    SuperResTestParam(96, 192),
+    SuperResTestParam(171, 192),
+    SuperResTestParam(102, 128),
+    SuperResTestParam(61, 121),
+};
+
+INSTANTIATE_TEST_SUITE_P(C, SuperResTest8bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, SuperResTest8bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, SuperResTest8bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using SuperResTest10bpp = SuperResTest<10, uint16_t, int16_t>;
+
+TEST_P(SuperResTest10bpp, FixedValues) {
+  TestComputeSuperRes(100, 1);
+  TestComputeSuperRes(511, 1);
+  TestComputeSuperRes(1, 1);
+}
+
+TEST_P(SuperResTest10bpp, RandomValues) { TestComputeSuperRes(0, 1); }
+
+TEST_P(SuperResTest10bpp, DISABLED_Speed) {
+  TestComputeSuperRes(0, kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, SuperResTest10bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, SuperResTest10bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, SuperResTest10bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using SuperResTest12bpp = SuperResTest<12, uint16_t, int16_t>;
+
+TEST_P(SuperResTest12bpp, FixedValues) {
+  TestComputeSuperRes(100, 1);
+  TestComputeSuperRes(2047, 1);
+  TestComputeSuperRes(1, 1);
+}
+
+TEST_P(SuperResTest12bpp, RandomValues) { TestComputeSuperRes(0, 1); }
+
+TEST_P(SuperResTest12bpp, DISABLED_Speed) {
+  TestComputeSuperRes(0, kNumSpeedTests);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, SuperResTest12bpp,
+                         testing::ValuesIn(kSuperResTestParams));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/warp_test.cc b/src/dsp/warp_test.cc
new file mode 100644
index 0000000..c64c8d6
--- /dev/null
+++ b/src/dsp/warp_test.cc
@@ -0,0 +1,710 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/warp.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/macros.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/post_filter.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kSourceBorderHorizontal = 16;
+constexpr int kSourceBorderVertical = 13;
+
+constexpr int kMaxSourceBlockWidth =
+    kMaxSuperBlockSizeInPixels + kSourceBorderHorizontal * 2;
+constexpr int kMaxSourceBlockHeight =
+    kMaxSuperBlockSizeInPixels + kSourceBorderVertical * 2;
+constexpr int kMaxDestBlockWidth =
+    kMaxSuperBlockSizeInPixels + kConvolveBorderLeftTop * 2;
+constexpr int kMaxDestBlockHeight =
+    kMaxSuperBlockSizeInPixels + kConvolveBorderLeftTop * 2;
+
+constexpr uint16_t kDivisorLookup[257] = {
+    16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
+    15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
+    15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
+    14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
+    13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
+    13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
+    13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
+    12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
+    12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
+    11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
+    11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
+    11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
+    10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
+    10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
+    10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
+    9963,  9939,  9916,  9892,  9869,  9846,  9823,  9800,  9777,  9754,  9732,
+    9709,  9687,  9664,  9642,  9620,  9598,  9576,  9554,  9533,  9511,  9489,
+    9468,  9447,  9425,  9404,  9383,  9362,  9341,  9321,  9300,  9279,  9259,
+    9239,  9218,  9198,  9178,  9158,  9138,  9118,  9098,  9079,  9059,  9039,
+    9020,  9001,  8981,  8962,  8943,  8924,  8905,  8886,  8867,  8849,  8830,
+    8812,  8793,  8775,  8756,  8738,  8720,  8702,  8684,  8666,  8648,  8630,
+    8613,  8595,  8577,  8560,  8542,  8525,  8508,  8490,  8473,  8456,  8439,
+    8422,  8405,  8389,  8372,  8355,  8339,  8322,  8306,  8289,  8273,  8257,
+    8240,  8224,  8208,  8192};
+
+template <bool is_compound>
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigest[] = {
+      "77ba358a0f5e19a8e69fa0a95712578e", "141b23d13a04e0b84d26d514de76d6b0",
+      "b0265858454b979852ffadae323f0fb7", "9cf38e3579265b656f1f2100ba15b0e9",
+      "ab51d05cc255ef8e37921182df1d89b1", "e3e96f90a4b07ca733e40f057dc01c41",
+      "4eee8c1a52a62a266db9b1c9338e124c", "901a87d8f88f6324dbc0960a6de861ac",
+      "da9cb6faf6adaeeae12b6784f39186c5", "14450ab05536cdb0d2f499716ccb559d",
+      "566b396cbf008bbb869b364fdc81860d", "681a872baf2de4e58d73ea9ab8643a72",
+      "7f17d290d513a7416761b3a01f10fd2f",
+  };
+  static const char* const kCompoundDigest[] = {
+      "7e9339d265b7beac7bbe32fe7bb0fccb", "f747d663b427bb38a3ff36b0815a394c",
+      "858cf54d2253281a919fbdb48fe91c53", "4721dd97a212c6068bd488f400259afc",
+      "36878c7906492bc740112abdea77616f", "89deb68aa35764bbf3024b501a6bed50",
+      "8ac5b08f9b2afd38143c357646af0f82", "bf6e2a64835ea0c9d7467394253d0eb2",
+      "7b0a539acd2a27eff398dd084abad933", "61c8d81b397c1cf727ff8a9fabab90af",
+      "4d412349a25a832c1fb3fb29e3f0e2b3", "2c6dd2a9a4ede9fa00adb567ba646f30",
+      "b2a0ce68db3cadd207299f73112bed74",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return is_compound ? kCompoundDigest[id] : kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+template <bool is_compound>
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigest[] = {
+      "1fef54f56a0bafccf7f8da1ac3b18b76", "8a65c72f171feafa2f393d31d6b7fe1b",
+      "808019346f2f1f45f8cf2e9fc9a49320", "c28e2f2c6c830a29bcc2452166cba521",
+      "f040674d6f54e8910d655f0d11fd8cdd", "473af9bb1c6023965c2284b716feef97",
+      "e4f6d7babd0813d5afb0f575ebfa8166", "58f96ef8a880963a213624bb0d06d47c",
+      "1ec0995fa4490628b679d03683233388", "9526fb102fde7dc1a7e160e65af6da33",
+      "f0457427d0c0e31d82ea4f612f7f86f1", "ddc82ae298cccebad493ba9de0f69fbd",
+      "5ed615091e2f62df26de7e91a985cb81",
+  };
+  static const char* const kCompoundDigest[] = {
+      "8e6986ae143260e0b8b4887f15a141a1", "0a7f0db8316b8c3569f08834dd0c6f50",
+      "90705b2e7dbe083e8a1f70f29d6f257e", "e428a75bea77d769d21f3f7a1d2b0b38",
+      "a570b13d790c085c4ab50d71dd085d56", "e5d043c6cd6ff6dbab6e38a8877e93bd",
+      "12ea96991e46e3e9aa78ab812ffa0525", "84293a94a53f1cf814fa25e793c3fe27",
+      "b98a7502c84ac8437266f702dcc0a92e", "d8db5d52e9b0a5be0ad2d517d5bd16e9",
+      "f3be504bbb609ce4cc71c5539252638a", "fcde83b54e14e9de23460644f244b047",
+      "42eb66e752e9ef289b47053b5c73fdd6",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return is_compound ? kCompoundDigest[id] : kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+template <bool is_compound>
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigest[] = {
+      "cd5d5e2102b8917ad70778f523d24bdf", "374a5f1b53a3fdf2eefa741eb71e6889",
+      "311636841770ec2427084891df96bee5", "c40c537917b1f0d1d84c99dfcecd8219",
+      "a1d9bb920e6c3d20c0cf84adc18e1f15", "13b5659acdb39b717526cb358c6f4026",
+      "f81ea4f6fd1f4ebed1262e3fae37b5bb", "c1452fefcd9b9562fe3a0b7f9302809c",
+      "8fed8a3159dc7b6b59a39ab2be6bee13", "b46458bc0e5cf1cee92aac4f0f608749",
+      "2e6a1039ab111add89f5b44b13565f40", "9c666691860bdc89b03f601b40126196",
+      "418a47157d992b94c302ca2e2f6ee07e",
+  };
+  static const char* const kCompoundDigest[] = {
+      "8e6986ae143260e0b8b4887f15a141a1", "0a7f0db8316b8c3569f08834dd0c6f50",
+      "90705b2e7dbe083e8a1f70f29d6f257e", "e428a75bea77d769d21f3f7a1d2b0b38",
+      "a570b13d790c085c4ab50d71dd085d56", "e5d043c6cd6ff6dbab6e38a8877e93bd",
+      "12ea96991e46e3e9aa78ab812ffa0525", "84293a94a53f1cf814fa25e793c3fe27",
+      "b98a7502c84ac8437266f702dcc0a92e", "d8db5d52e9b0a5be0ad2d517d5bd16e9",
+      "f3be504bbb609ce4cc71c5539252638a", "fcde83b54e14e9de23460644f244b047",
+      "42eb66e752e9ef289b47053b5c73fdd6",
+  };
+  assert(id >= 0);
+  assert(id < sizeof(kDigest) / sizeof(kDigest[0]));
+  return is_compound ? kCompoundDigest[id] : kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+int RandomWarpedParam(int seed_offset, int bits) {
+  libvpx_test::ACMRandom rnd(seed_offset +
+                             libvpx_test::ACMRandom::DeterministicSeed());
+  // 1 in 8 chance of generating zero (arbitrary).
+  const bool zero = (rnd.Rand16() & 7) == 0;
+  if (zero) return 0;
+  // Generate uniform values in the range [-(1 << bits), 1] U [1, 1 <<
+  // bits].
+  const int mask = (1 << bits) - 1;
+  const int value = 1 + (rnd.RandRange(1u << 31) & mask);
+  const bool sign = (rnd.Rand16() & 1) != 0;
+  return sign ? value : -value;
+}
+
+// This function is a copy from warp_prediction.cc.
+template <typename T>
+void GenerateApproximateDivisor(T value, int16_t* division_factor,
+                                int16_t* division_shift) {
+  const int n = FloorLog2(std::abs(value));
+  const T e = std::abs(value) - (static_cast<T>(1) << n);
+  const int entry = (n > kDivisorLookupBits)
+                        ? RightShiftWithRounding(e, n - kDivisorLookupBits)
+                        : static_cast<int>(e << (kDivisorLookupBits - n));
+  *division_shift = n + kDivisorLookupPrecisionBits;
+  *division_factor =
+      (value < 0) ? -kDivisorLookup[entry] : kDivisorLookup[entry];
+}
+
+// This function is a copy from warp_prediction.cc.
+int16_t GetShearParameter(int value) {
+  return static_cast<int16_t>(
+      LeftShift(RightShiftWithRoundingSigned(value, kWarpParamRoundingBits),
+                kWarpParamRoundingBits));
+}
+
+// This function is a copy from warp_prediction.cc.
+// This function is used here to help generate valid warp parameters.
+bool SetupShear(const int* params, int16_t* alpha, int16_t* beta,
+                int16_t* gamma, int16_t* delta) {
+  int16_t division_shift;
+  int16_t division_factor;
+  GenerateApproximateDivisor<int32_t>(params[2], &division_factor,
+                                      &division_shift);
+  const int alpha0 =
+      Clip3(params[2] - (1 << kWarpedModelPrecisionBits), INT16_MIN, INT16_MAX);
+  const int beta0 = Clip3(params[3], INT16_MIN, INT16_MAX);
+  const int64_t v = LeftShift(params[4], kWarpedModelPrecisionBits);
+  const int gamma0 =
+      Clip3(RightShiftWithRoundingSigned(v * division_factor, division_shift),
+            INT16_MIN, INT16_MAX);
+  const int64_t w = static_cast<int64_t>(params[3]) * params[4];
+  const int delta0 = Clip3(
+      params[5] -
+          RightShiftWithRoundingSigned(w * division_factor, division_shift) -
+          (1 << kWarpedModelPrecisionBits),
+      INT16_MIN, INT16_MAX);
+
+  *alpha = GetShearParameter(alpha0);
+  *beta = GetShearParameter(beta0);
+  *gamma = GetShearParameter(gamma0);
+  *delta = GetShearParameter(delta0);
+  if ((4 * std::abs(*alpha) + 7 * std::abs(*beta) >=
+       (1 << kWarpedModelPrecisionBits)) ||
+      (4 * std::abs(*gamma) + 4 * std::abs(*delta) >=
+       (1 << kWarpedModelPrecisionBits))) {
+    return false;  // NOLINT (easier condition to understand).
+  }
+
+  return true;
+}
+
+void GenerateWarpedModel(int* params, int16_t* alpha, int16_t* beta,
+                         int16_t* gamma, int16_t* delta, int seed) {
+  do {
+    params[0] = RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+    params[1] = RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+    params[2] = RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+                (1 << kWarpedModelPrecisionBits);
+    params[3] = RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+    params[4] = RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+    params[5] = RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+                (1 << kWarpedModelPrecisionBits);
+    ++seed;
+  } while (params[2] == 0 || !SetupShear(params, alpha, beta, gamma, delta));
+}
+
+struct WarpTestParam {
+  WarpTestParam(int width, int height) : width(width), height(height) {}
+  int width;
+  int height;
+};
+
+template <bool is_compound, int bitdepth, typename Pixel>
+class WarpTest : public testing::TestWithParam<WarpTestParam> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  WarpTest() = default;
+  ~WarpTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    WarpInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const absl::string_view test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      WarpInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      WarpInit_SSE4_1();
+    } else {
+      FAIL() << "Unrecognized architecture prefix in test case name: "
+             << test_case;
+    }
+    func_ = is_compound ? dsp->warp_compound : dsp->warp;
+  }
+
+ protected:
+  using DestType =
+      typename std::conditional<is_compound, uint16_t, Pixel>::type;
+
+  void SetInputData(bool use_fixed_values, int value);
+  void Test(bool use_fixed_values, int value, int num_runs = 1);
+  void TestFixedValues();
+  void TestRandomValues();
+  void TestSpeed();
+
+  const WarpTestParam param_ = GetParam();
+
+ private:
+  int warp_params_[8];
+  dsp::WarpFunc func_;
+  // Warp filters are 7-tap, which needs 3 pixels (kConvolveBorderLeftTop)
+  // padding. Destination buffer indices are based on subsampling values (x+y):
+  // 0: (4:4:4), 1:(4:2:2), 2: (4:2:0).
+  Pixel source_[kMaxSourceBlockHeight * kMaxSourceBlockWidth] = {};
+  DestType dest_[3][kMaxDestBlockHeight * kMaxDestBlockWidth] = {};
+};
+
+template <bool is_compound, int bitdepth, typename Pixel>
+void WarpTest<is_compound, bitdepth, Pixel>::SetInputData(bool use_fixed_values,
+                                                          int value) {
+  if (use_fixed_values) {
+    for (int y = 0; y < param_.height; ++y) {
+      const int row = kSourceBorderVertical + y;
+      Memset(source_ + row * kMaxSourceBlockWidth + kSourceBorderHorizontal,
+             value, param_.width);
+    }
+  } else {
+    const int mask = (1 << bitdepth) - 1;
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    for (int y = 0; y < param_.height; ++y) {
+      const int row = kSourceBorderVertical + y;
+      for (int x = 0; x < param_.width; ++x) {
+        const int column = kSourceBorderHorizontal + x;
+        source_[row * kMaxSourceBlockWidth + column] = rnd.Rand16() & mask;
+      }
+    }
+  }
+  PostFilter::ExtendFrame<Pixel>(
+      &source_[kSourceBorderVertical * kMaxSourceBlockWidth +
+               kSourceBorderHorizontal],
+      param_.width, param_.height, kMaxSourceBlockWidth,
+      kSourceBorderHorizontal, kSourceBorderHorizontal, kSourceBorderVertical,
+      kSourceBorderVertical);
+}
+
+template <bool is_compound, int bitdepth, typename Pixel>
+void WarpTest<is_compound, bitdepth, Pixel>::Test(bool use_fixed_values,
+                                                  int value,
+                                                  int num_runs /*= 1*/) {
+  if (func_ == nullptr) return;
+  SetInputData(use_fixed_values, value);
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  const int source_offset =
+      kSourceBorderVertical * kMaxSourceBlockWidth + kSourceBorderHorizontal;
+  const int dest_offset =
+      kConvolveBorderLeftTop * kMaxDestBlockWidth + kConvolveBorderLeftTop;
+  const Pixel* const src = source_ + source_offset;
+  const ptrdiff_t src_stride = kMaxSourceBlockWidth * sizeof(Pixel);
+  const ptrdiff_t dst_stride =
+      is_compound ? kMaxDestBlockWidth : kMaxDestBlockWidth * sizeof(Pixel);
+
+  absl::Duration elapsed_time;
+  for (int subsampling_x = 0; subsampling_x <= 1; ++subsampling_x) {
+    for (int subsampling_y = 0; subsampling_y <= 1; ++subsampling_y) {
+      if (subsampling_x == 0 && subsampling_y == 1) {
+        // When both are 0: 4:4:4
+        // When both are 1: 4:2:0
+        // When only |subsampling_x| is 1: 4:2:2
+        // Having only |subsampling_y| == 1 is unsupported.
+        continue;
+      }
+      int params[8];
+      int16_t alpha;
+      int16_t beta;
+      int16_t gamma;
+      int16_t delta;
+      GenerateWarpedModel(params, &alpha, &beta, &gamma, &delta, rnd.Rand8());
+
+      const int dest_id = subsampling_x + subsampling_y;
+      DestType* const dst = dest_[dest_id] + dest_offset;
+      const absl::Time start = absl::Now();
+      for (int n = 0; n < num_runs; ++n) {
+        func_(src, src_stride, param_.width, param_.height, params,
+              subsampling_x, subsampling_y, 0, 0, param_.width, param_.height,
+              alpha, beta, gamma, delta, dst, dst_stride);
+      }
+      elapsed_time += absl::Now() - start;
+    }
+  }
+
+  if (use_fixed_values) {
+    // For fixed values, input and output are identical.
+    for (size_t i = 0; i < ABSL_ARRAYSIZE(dest_); ++i) {
+      // |is_compound| holds a few more bits of precision and an offset value.
+      Pixel compensated_dest[kMaxDestBlockWidth * kMaxDestBlockHeight];
+      const int compound_offset = (bitdepth == 8) ? 0 : kCompoundOffset;
+      if (is_compound) {
+        for (int y = 0; y < param_.height; ++y) {
+          for (int x = 0; x < param_.width; ++x) {
+            const int compound_value =
+                dest_[i][dest_offset + y * kMaxDestBlockWidth + x];
+            const int remove_offset = compound_value - compound_offset;
+            const int full_shift =
+                remove_offset >>
+                (kInterRoundBitsVertical - kInterRoundBitsCompoundVertical);
+            compensated_dest[y * kMaxDestBlockWidth + x] =
+                Clip3(full_shift, 0, (1 << bitdepth) - 1);
+          }
+        }
+      }
+      Pixel* pixel_dest =
+          is_compound ? compensated_dest
+                      : reinterpret_cast<Pixel*>(dest_[i] + dest_offset);
+      const bool success = test_utils::CompareBlocks(
+          src, pixel_dest, param_.width, param_.height, kMaxSourceBlockWidth,
+          kMaxDestBlockWidth, false);
+      EXPECT_TRUE(success) << "subsampling_x + subsampling_y: " << i;
+    }
+  } else {
+    // (width, height):
+    // (8, 8), id = 0. (8, 16), id = 1. (16, 8), id = 2.
+    // (16, 16), id = 3. (16, 32), id = 4. (32, 16), id = 5.
+    // ...
+    // (128, 128), id = 12.
+    int id;
+    if (param_.width == param_.height) {
+      id = 3 * static_cast<int>(FloorLog2(param_.width) - 3);
+    } else if (param_.width < param_.height) {
+      id = 1 + 3 * static_cast<int>(FloorLog2(param_.width) - 3);
+    } else {
+      id = 2 + 3 * static_cast<int>(FloorLog2(param_.height) - 3);
+    }
+
+    const char* expected_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        expected_digest = GetDigest8bpp<is_compound>(id);
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        expected_digest = GetDigest10bpp<is_compound>(id);
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        expected_digest = GetDigest12bpp<is_compound>(id);
+        break;
+#endif
+    }
+    ASSERT_NE(expected_digest, nullptr);
+    test_utils::CheckMd5Digest(
+        "Warp", absl::StrFormat("%dx%d", param_.width, param_.height).c_str(),
+        expected_digest, dest_, sizeof(dest_), elapsed_time);
+  }
+}
+
+template <bool is_compound, int bitdepth, typename Pixel>
+void WarpTest<is_compound, bitdepth, Pixel>::TestFixedValues() {
+  Test(true, 0);
+  Test(true, 1);
+  Test(true, 128);
+  Test(true, (1 << bitdepth) - 1);
+}
+
+template <bool is_compound, int bitdepth, typename Pixel>
+void WarpTest<is_compound, bitdepth, Pixel>::TestRandomValues() {
+  Test(false, 0);
+}
+
+template <bool is_compound, int bitdepth, typename Pixel>
+void WarpTest<is_compound, bitdepth, Pixel>::TestSpeed() {
+  const int num_runs = static_cast<int>(1.0e7 / (param_.width * param_.height));
+  Test(false, 0, num_runs);
+}
+
+void ApplyFilterToSignedInput(const int min_input, const int max_input,
+                              const int8_t filter[kSubPixelTaps],
+                              int* min_output, int* max_output) {
+  int min = 0, max = 0;
+  for (int i = 0; i < kSubPixelTaps; ++i) {
+    const int tap = filter[i];
+    if (tap > 0) {
+      max += max_input * tap;
+      min += min_input * tap;
+    } else {
+      min += max_input * tap;
+      max += min_input * tap;
+    }
+  }
+  *min_output = min;
+  *max_output = max;
+}
+
+void ApplyFilterToUnsignedInput(const int max_input,
+                                const int8_t filter[kSubPixelTaps],
+                                int* min_output, int* max_output) {
+  ApplyFilterToSignedInput(0, max_input, filter, min_output, max_output);
+}
+
+// Validate the maximum ranges for different parts of the Warp process.
+template <int bitdepth>
+void ShowRange() {
+  constexpr int horizontal_bits = (bitdepth == kBitdepth12)
+                                      ? kInterRoundBitsHorizontal12bpp
+                                      : kInterRoundBitsHorizontal;
+  constexpr int vertical_bits = (bitdepth == kBitdepth12)
+                                    ? kInterRoundBitsVertical12bpp
+                                    : kInterRoundBitsVertical;
+  constexpr int compound_vertical_bits = kInterRoundBitsCompoundVertical;
+
+  constexpr int compound_offset = (bitdepth == 8) ? 0 : kCompoundOffset;
+
+  constexpr int max_input = (1 << bitdepth) - 1;
+
+  const int8_t* worst_warp_filter = kWarpedFilters8[93];
+
+  // First pass.
+  printf("Bitdepth: %2d Input range:            [%8d, %8d]\n", bitdepth, 0,
+         max_input);
+
+  int min = 0, max = 0;
+  ApplyFilterToUnsignedInput(max_input, worst_warp_filter, &min, &max);
+
+  int first_pass_offset;
+  if (bitdepth == 8) {
+    // Derive an offset for 8 bit.
+    for (first_pass_offset = 1; - first_pass_offset > min;
+         first_pass_offset <<= 1) {
+    }
+    printf("  8bpp intermediate offset: %d.\n", first_pass_offset);
+    min += first_pass_offset;
+    max += first_pass_offset;
+    assert(min > 0);
+    assert(max < UINT16_MAX);
+  } else {
+    // 10bpp and 12bpp require int32_t for the intermediate values. Adding an
+    // offset is not required.
+    assert(min > INT32_MIN);
+    assert(max > INT16_MAX && max < INT32_MAX);
+  }
+
+  printf("  intermediate range:                [%8d, %8d]\n", min, max);
+
+  const int first_pass_min = RightShiftWithRounding(min, horizontal_bits);
+  const int first_pass_max = RightShiftWithRounding(max, horizontal_bits);
+
+  printf("  first pass output range:           [%8d, %8d]\n", first_pass_min,
+         first_pass_max);
+
+  // Second pass.
+  if (bitdepth == 8) {
+    ApplyFilterToUnsignedInput(first_pass_max, worst_warp_filter, &min, &max);
+  } else {
+    ApplyFilterToSignedInput(first_pass_min, first_pass_max, worst_warp_filter,
+                             &min, &max);
+  }
+
+  if (bitdepth == 8) {
+    // Remove the offset that was applied in the first pass since we must use
+    // int32_t for this phase anyway. 128 is the sum of the filter taps.
+    const int offset_removal = (first_pass_offset >> horizontal_bits) * 128;
+    printf("  8bpp intermediate offset removal: %d.\n", offset_removal);
+    max -= offset_removal;
+    min -= offset_removal;
+    assert(min < INT16_MIN && min > INT32_MIN);
+    assert(max > INT16_MAX && max < INT32_MAX);
+  } else {
+    // 10bpp and 12bpp require int32_t for the intermediate values. Adding an
+    // offset is not required.
+    assert(min > INT32_MIN);
+    assert(max > INT16_MAX && max < INT32_MAX);
+  }
+
+  printf("  intermediate range:                [%8d, %8d]\n", min, max);
+
+  // Second pass non-compound output is clipped to Pixel values.
+  const int second_pass_min =
+      Clip3(RightShiftWithRounding(min, vertical_bits), 0, max_input);
+  const int second_pass_max =
+      Clip3(RightShiftWithRounding(max, vertical_bits), 0, max_input);
+  printf("  second pass output range:          [%8d, %8d]\n", second_pass_min,
+         second_pass_max);
+
+  // Output is Pixel so matches Pixel values.
+  assert(second_pass_min == 0);
+  assert(second_pass_max == max_input);
+
+  const int compound_second_pass_min =
+      RightShiftWithRounding(min, compound_vertical_bits) + compound_offset;
+  const int compound_second_pass_max =
+      RightShiftWithRounding(max, compound_vertical_bits) + compound_offset;
+
+  printf("  compound second pass output range: [%8d, %8d]\n",
+         compound_second_pass_min, compound_second_pass_max);
+
+  if (bitdepth == 8) {
+    // 8bpp output is int16_t without an offset.
+    assert(compound_second_pass_min > INT16_MIN);
+    assert(compound_second_pass_max < INT16_MAX);
+  } else {
+    // 10bpp and 12bpp use the offset to fit inside uint16_t.
+    assert(compound_second_pass_min > 0);
+    assert(compound_second_pass_max < UINT16_MAX);
+  }
+
+  printf("\n");
+}
+
+TEST(WarpTest, ShowRange) {
+  ShowRange<kBitdepth8>();
+  ShowRange<kBitdepth10>();
+  ShowRange<kBitdepth12>();
+}
+
+using WarpTest8bpp = WarpTest</*is_compound=*/false, 8, uint8_t>;
+// TODO(jzern): Coverage could be added for kInterRoundBitsCompoundVertical via
+// WarpCompoundTest.
+// using WarpCompoundTest8bpp = WarpTest</*is_compound=*/true, 8, uint8_t>;
+
+// Verifies the sum of the warped filter coefficients is 128 for every filter.
+//
+// Verifies the properties used in the calculation of ranges of variables in
+// the block warp process:
+// * The maximum sum of the positive warped filter coefficients is 175.
+// * The minimum (i.e., most negative) sum of the negative warped filter
+//   coefficients is -47.
+//
+// NOTE: This test is independent of the bitdepth and the implementation of the
+// block warp function, so it just needs to be a test in the WarpTest8bpp class
+// and does not need to be defined with TEST_P.
+TEST(WarpTest8bpp, WarpedFilterCoefficientSums) {
+  int max_positive_sum = 0;
+  int min_negative_sum = 0;
+  for (const auto& filter : kWarpedFilters) {
+    int sum = 0;
+    int positive_sum = 0;
+    int negative_sum = 0;
+    for (const auto coefficient : filter) {
+      sum += coefficient;
+      if (coefficient > 0) {
+        positive_sum += coefficient;
+      } else {
+        negative_sum += coefficient;
+      }
+    }
+    EXPECT_EQ(sum, 128);
+    max_positive_sum = std::max(positive_sum, max_positive_sum);
+    min_negative_sum = std::min(negative_sum, min_negative_sum);
+  }
+  EXPECT_EQ(max_positive_sum, 175);
+  EXPECT_EQ(min_negative_sum, -47);
+}
+
+TEST_P(WarpTest8bpp, FixedValues) { TestFixedValues(); }
+
+TEST_P(WarpTest8bpp, RandomValues) { TestRandomValues(); }
+
+TEST_P(WarpTest8bpp, DISABLED_Speed) { TestSpeed(); }
+const WarpTestParam warp_test_param[] = {
+    WarpTestParam(8, 8),     WarpTestParam(8, 16),   WarpTestParam(16, 8),
+    WarpTestParam(16, 16),   WarpTestParam(16, 32),  WarpTestParam(32, 16),
+    WarpTestParam(32, 32),   WarpTestParam(32, 64),  WarpTestParam(64, 32),
+    WarpTestParam(64, 64),   WarpTestParam(64, 128), WarpTestParam(128, 64),
+    WarpTestParam(128, 128),
+};
+
+INSTANTIATE_TEST_SUITE_P(C, WarpTest8bpp, testing::ValuesIn(warp_test_param));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WarpTest8bpp,
+                         testing::ValuesIn(warp_test_param));
+#endif
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, WarpTest8bpp,
+                         testing::ValuesIn(warp_test_param));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using WarpTest10bpp = WarpTest</*is_compound=*/false, 10, uint16_t>;
+// TODO(jzern): Coverage could be added for kInterRoundBitsCompoundVertical via
+// WarpCompoundTest.
+// using WarpCompoundTest10bpp = WarpTest</*is_compound=*/true, 10, uint16_t>;
+
+TEST_P(WarpTest10bpp, FixedValues) { TestFixedValues(); }
+
+TEST_P(WarpTest10bpp, RandomValues) { TestRandomValues(); }
+
+TEST_P(WarpTest10bpp, DISABLED_Speed) { TestSpeed(); }
+
+INSTANTIATE_TEST_SUITE_P(C, WarpTest10bpp, testing::ValuesIn(warp_test_param));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WarpTest10bpp,
+                         testing::ValuesIn(warp_test_param));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using WarpTest12bpp = WarpTest</*is_compound=*/false, 12, uint16_t>;
+// TODO(jzern): Coverage could be added for kInterRoundBitsCompoundVertical via
+// WarpCompoundTest.
+// using WarpCompoundTest12bpp = WarpTest</*is_compound=*/true, 12, uint16_t>;
+
+TEST_P(WarpTest12bpp, FixedValues) { TestFixedValues(); }
+
+TEST_P(WarpTest12bpp, RandomValues) { TestRandomValues(); }
+
+TEST_P(WarpTest12bpp, DISABLED_Speed) { TestSpeed(); }
+
+INSTANTIATE_TEST_SUITE_P(C, WarpTest12bpp, testing::ValuesIn(warp_test_param));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+std::ostream& operator<<(std::ostream& os, const WarpTestParam& warp_param) {
+  return os << "BlockSize" << warp_param.width << "x" << warp_param.height;
+}
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/weight_mask_test.cc b/src/dsp/weight_mask_test.cc
new file mode 100644
index 0000000..74ec03c
--- /dev/null
+++ b/src/dsp/weight_mask_test.cc
@@ -0,0 +1,467 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/weight_mask.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+constexpr int kNumSpeedTests = 50000;
+constexpr int kMaxPredictionSize = 128;
+// weight_mask is only used with kCompoundPredictionTypeDiffWeighted with
+// convolve producing the most extreme ranges.
+// This includes kCompoundOffset in 10bpp and 12bpp.
+// see: src/dsp/convolve.cc & src/dsp/warp.cc.
+constexpr int kCompoundPredictionRange[3][2] = {
+    // 8bpp
+    {-5132, 9212},
+    // 10bpp
+    {3988, 61532},
+    // 12bpp
+    {3974, 61559},
+};
+
+const char* GetDigest8bpp(int id) {
+  static const char* const kDigest[] = {
+      "eaca5b6a96dcfe5e44f3926a071b48b3",
+      "1d82c75cfdf8e57925eb1d5301647538",
+      "25bd455d74fb891b97b133c528f8db60",
+      "" /*kBlock4x16*/,
+      "1d82c75cfdf8e57925eb1d5301647538",
+      "25bd455d74fb891b97b133c528f8db60",
+      "62a08776db35a186406a11ab92dee71c",
+      "95131d1dc0e05fcf4bd234d5ce9eea11",
+      "25bd455d74fb891b97b133c528f8db60",
+      "62a08776db35a186406a11ab92dee71c",
+      "95131d1dc0e05fcf4bd234d5ce9eea11",
+      "0b3c75272e0fb0747b9850145d340c4c",
+      "95131d1dc0e05fcf4bd234d5ce9eea11",
+      "0b3c75272e0fb0747b9850145d340c4c",
+      "f26c43d4bc823a89c1ed47ab8708bc06",
+      "0d99bbf31ecddc1c2d5063a68c0e9375",
+      "0d99bbf31ecddc1c2d5063a68c0e9375",
+      "5fb8ec5f582f0ebfe519ed55860f67c4",
+
+      // mask_is_inverse = true.
+      "96811f3b192828ff679e4c9ad8069d7d",
+      "a04dc180c028d55af70240163445523a",
+      "8513e3988233d0a7de316a0179bb6139",
+      "" /*kBlock4x16*/,
+      "a04dc180c028d55af70240163445523a",
+      "8513e3988233d0a7de316a0179bb6139",
+      "f7356d42fb44a6ccb41253ba35b8b3c7",
+      "3d2d61ffc203ee64fe91c9d16168a19d",
+      "8513e3988233d0a7de316a0179bb6139",
+      "f7356d42fb44a6ccb41253ba35b8b3c7",
+      "3d2d61ffc203ee64fe91c9d16168a19d",
+      "87a2011ac69fb597ca4f71bb3c35ebb0",
+      "3d2d61ffc203ee64fe91c9d16168a19d",
+      "87a2011ac69fb597ca4f71bb3c35ebb0",
+      "97100a3639d567046dc8a99fcb84cb2e",
+      "9fabe05a6523da81a45150e19f75acff",
+      "9fabe05a6523da81a45150e19f75acff",
+      "7c0643e4d02421d06d7ca71822a94e1d",
+  };
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigest10bpp(int id) {
+  static const char* const kDigest[] = {
+      "5ae8d64b65a671301a457b8a73368ab5",
+      "61535217f179054d4b76a8d9352a223d",
+      "1aa6614773570e7b021cd509849c4180",
+      "" /*kBlock4x16*/,
+      "61535217f179054d4b76a8d9352a223d",
+      "1aa6614773570e7b021cd509849c4180",
+      "f04c2825cfb6408c7778658f71fa176e",
+      "e1694ea1f026dac7fe7e86a84482cf86",
+      "1aa6614773570e7b021cd509849c4180",
+      "f04c2825cfb6408c7778658f71fa176e",
+      "e1694ea1f026dac7fe7e86a84482cf86",
+      "9c4855d44c013fbddb373b2e9e311080",
+      "e1694ea1f026dac7fe7e86a84482cf86",
+      "9c4855d44c013fbddb373b2e9e311080",
+      "f510e743c3efe3b83374a98ef8a30838",
+      "b6e0bd03c521c5f00e90530daa7d4432",
+      "b6e0bd03c521c5f00e90530daa7d4432",
+      "3270d7f621d488aec5b76bcf121debd0",
+
+      // mask_is_inverse = true.
+      "9aa00fcfe21b71e30c5393699122a020",
+      "4d8ce33262cf6b5375f363530815189a",
+      "428625c51ac1bd4585988f7b36dff1db",
+      "" /*kBlock4x16*/,
+      "4d8ce33262cf6b5375f363530815189a",
+      "428625c51ac1bd4585988f7b36dff1db",
+      "1ef63c06a2d9c42da293fdf924032981",
+      "5dd3f201d755d1c22c126a633bfbb3c0",
+      "428625c51ac1bd4585988f7b36dff1db",
+      "1ef63c06a2d9c42da293fdf924032981",
+      "5dd3f201d755d1c22c126a633bfbb3c0",
+      "fe1e6843e6f214939da516dcbea04a79",
+      "5dd3f201d755d1c22c126a633bfbb3c0",
+      "fe1e6843e6f214939da516dcbea04a79",
+      "240187f27389b5e89f9ec6bdbd7d20a7",
+      "44925dab01011a98b8ab1f0308fa852a",
+      "44925dab01011a98b8ab1f0308fa852a",
+      "6d984b2ccfa056278e2130771127a943",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigest12bpp(int id) {
+  static const char* const kDigest[] = {
+      "57629d3872fd52ff4bbec439c5517ec5",
+      "dba421ceeb534756c77167e00ae91a2c",
+      "72e8ac1d450ef0c6c6b03e93856d5cc2",
+      "" /*kBlock4x16*/,
+      "dba421ceeb534756c77167e00ae91a2c",
+      "72e8ac1d450ef0c6c6b03e93856d5cc2",
+      "ae573eb368df04e6a0133b4e15471728",
+      "ceede597b2729357b15e0d08bb9bb760",
+      "72e8ac1d450ef0c6c6b03e93856d5cc2",
+      "ae573eb368df04e6a0133b4e15471728",
+      "ceede597b2729357b15e0d08bb9bb760",
+      "c4976af803d7ad3f92ef26f25b9f3754",
+      "ceede597b2729357b15e0d08bb9bb760",
+      "c4976af803d7ad3f92ef26f25b9f3754",
+      "1d957d49f71bb7f304705a11a597f0cb",
+      "9522d5713fb951b79f42d78fbff914cf",
+      "9522d5713fb951b79f42d78fbff914cf",
+      "422c046013f79a9f46e2c855967570ba",
+
+      // mask_is_inverse = true.
+      "a585cca9bc459d10e081bc0eb847b6e3",
+      "2fa4ec5f74fad2831d216c51c2cdad5a",
+      "d6c9ac69a9eb3059f5bb6e42b486ebcd",
+      "" /*kBlock4x16*/,
+      "2fa4ec5f74fad2831d216c51c2cdad5a",
+      "d6c9ac69a9eb3059f5bb6e42b486ebcd",
+      "2ddd8c8a1841501964011030e2557e20",
+      "97ef2575023dda008711015cf08d7590",
+      "d6c9ac69a9eb3059f5bb6e42b486ebcd",
+      "2ddd8c8a1841501964011030e2557e20",
+      "97ef2575023dda008711015cf08d7590",
+      "d69aff1e0d43395ce305c9be0dfb4c89",
+      "97ef2575023dda008711015cf08d7590",
+      "d69aff1e0d43395ce305c9be0dfb4c89",
+      "48786f640191dcbee5b3321672778519",
+      "6ad4718230353440b01f2bb78348157e",
+      "6ad4718230353440b01f2bb78348157e",
+      "ad49bd7af0ea17c84f434c7dfd0a911d",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct WeightMaskTestParam {
+  WeightMaskTestParam(int width, int height, bool mask_is_inverse)
+      : width(width), height(height), mask_is_inverse(mask_is_inverse) {}
+  int width;
+  int height;
+  bool mask_is_inverse;
+};
+
+std::ostream& operator<<(std::ostream& os, const WeightMaskTestParam& param) {
+  return os << param.width << "x" << param.height
+            << ", mask_is_inverse: " << param.mask_is_inverse;
+}
+
+template <int bitdepth>
+class WeightMaskTest : public testing::TestWithParam<WeightMaskTestParam>,
+                       public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  WeightMaskTest() = default;
+  ~WeightMaskTest() override = default;
+
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    WeightMaskInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp, nullptr);
+    const int width_index = FloorLog2(width_) - 3;
+    const int height_index = FloorLog2(height_) - 3;
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+      WeightMaskInit_NEON();
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      WeightMaskInit_SSE4_1();
+    }
+    func_ = dsp->weight_mask[width_index][height_index][mask_is_inverse_];
+  }
+
+ protected:
+  void SetInputData(bool use_fixed_values, int value_1, int value_2);
+  void Test(int num_runs, bool use_fixed_values, int value_1, int value_2);
+
+ private:
+  const int width_ = GetParam().width;
+  const int height_ = GetParam().height;
+  const bool mask_is_inverse_ = GetParam().mask_is_inverse;
+  using PredType =
+      typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
+  alignas(
+      kMaxAlignment) PredType block_1_[kMaxPredictionSize * kMaxPredictionSize];
+  alignas(
+      kMaxAlignment) PredType block_2_[kMaxPredictionSize * kMaxPredictionSize];
+  uint8_t mask_[kMaxPredictionSize * kMaxPredictionSize] = {};
+  dsp::WeightMaskFunc func_;
+};
+
+template <int bitdepth>
+void WeightMaskTest<bitdepth>::SetInputData(const bool use_fixed_values,
+                                            const int value_1,
+                                            const int value_2) {
+  if (use_fixed_values) {
+    std::fill(block_1_, block_1_ + kMaxPredictionSize * kMaxPredictionSize,
+              value_1);
+    std::fill(block_2_, block_2_ + kMaxPredictionSize * kMaxPredictionSize,
+              value_2);
+  } else {
+    constexpr int bitdepth_index = (bitdepth - 8) >> 1;
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    for (int y = 0; y < height_; ++y) {
+      for (int x = 0; x < width_; ++x) {
+        const int min_val = kCompoundPredictionRange[bitdepth_index][0];
+        const int max_val = kCompoundPredictionRange[bitdepth_index][1];
+        block_1_[y * width_ + x] =
+            static_cast<PredType>(rnd(max_val - min_val) + min_val);
+        block_2_[y * width_ + x] =
+            static_cast<PredType>(rnd(max_val - min_val) + min_val);
+      }
+    }
+  }
+}
+
+BlockSize DimensionsToBlockSize(int width, int height) {
+  if (width == 4) {
+    if (height == 4) return kBlock4x4;
+    if (height == 8) return kBlock4x8;
+    if (height == 16) return kBlock4x16;
+    return kBlockInvalid;
+  }
+  if (width == 8) {
+    if (height == 4) return kBlock8x4;
+    if (height == 8) return kBlock8x8;
+    if (height == 16) return kBlock8x16;
+    if (height == 32) return kBlock8x32;
+    return kBlockInvalid;
+  }
+  if (width == 16) {
+    if (height == 4) return kBlock16x4;
+    if (height == 8) return kBlock16x8;
+    if (height == 16) return kBlock16x16;
+    if (height == 32) return kBlock16x32;
+    if (height == 64) return kBlock16x64;
+    return kBlockInvalid;
+  }
+  if (width == 32) {
+    if (height == 8) return kBlock32x8;
+    if (height == 16) return kBlock32x16;
+    if (height == 32) return kBlock32x32;
+    if (height == 64) return kBlock32x64;
+    return kBlockInvalid;
+  }
+  if (width == 64) {
+    if (height == 16) return kBlock64x16;
+    if (height == 32) return kBlock64x32;
+    if (height == 64) return kBlock64x64;
+    if (height == 128) return kBlock64x128;
+    return kBlockInvalid;
+  }
+  if (width == 128) {
+    if (height == 64) return kBlock128x64;
+    if (height == 128) return kBlock128x128;
+    return kBlockInvalid;
+  }
+  return kBlockInvalid;
+}
+
+template <int bitdepth>
+void WeightMaskTest<bitdepth>::Test(const int num_runs,
+                                    const bool use_fixed_values,
+                                    const int value_1, const int value_2) {
+  if (func_ == nullptr) return;
+  SetInputData(use_fixed_values, value_1, value_2);
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    func_(block_1_, block_2_, mask_, width_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (use_fixed_values) {
+    int fixed_value = (value_1 - value_2 == 0) ? 38 : 64;
+    if (mask_is_inverse_) fixed_value = 64 - fixed_value;
+    for (int y = 0; y < height_; ++y) {
+      for (int x = 0; x < width_; ++x) {
+        ASSERT_EQ(static_cast<int>(mask_[y * width_ + x]), fixed_value)
+            << "x: " << x << " y: " << y;
+      }
+    }
+  } else {
+    const int id_offset = mask_is_inverse_ ? kMaxBlockSizes - 4 : 0;
+    const int id = id_offset +
+                   static_cast<int>(DimensionsToBlockSize(width_, height_)) - 4;
+    const char* expected_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        expected_digest = GetDigest8bpp(id);
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        expected_digest = GetDigest10bpp(id);
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        expected_digest = GetDigest12bpp(id);
+        break;
+#endif
+    }
+    ASSERT_NE(expected_digest, nullptr);
+    test_utils::CheckMd5Digest(
+        absl::StrFormat("BlockSize %dx%d", width_, height_).c_str(),
+        "WeightMask", expected_digest, mask_, sizeof(mask_), elapsed_time);
+  }
+}
+
+const WeightMaskTestParam weight_mask_test_param[] = {
+    WeightMaskTestParam(8, 8, false),     WeightMaskTestParam(8, 16, false),
+    WeightMaskTestParam(8, 32, false),    WeightMaskTestParam(16, 8, false),
+    WeightMaskTestParam(16, 16, false),   WeightMaskTestParam(16, 32, false),
+    WeightMaskTestParam(16, 64, false),   WeightMaskTestParam(32, 8, false),
+    WeightMaskTestParam(32, 16, false),   WeightMaskTestParam(32, 32, false),
+    WeightMaskTestParam(32, 64, false),   WeightMaskTestParam(64, 16, false),
+    WeightMaskTestParam(64, 32, false),   WeightMaskTestParam(64, 64, false),
+    WeightMaskTestParam(64, 128, false),  WeightMaskTestParam(128, 64, false),
+    WeightMaskTestParam(128, 128, false), WeightMaskTestParam(8, 8, true),
+    WeightMaskTestParam(8, 16, true),     WeightMaskTestParam(8, 32, true),
+    WeightMaskTestParam(16, 8, true),     WeightMaskTestParam(16, 16, true),
+    WeightMaskTestParam(16, 32, true),    WeightMaskTestParam(16, 64, true),
+    WeightMaskTestParam(32, 8, true),     WeightMaskTestParam(32, 16, true),
+    WeightMaskTestParam(32, 32, true),    WeightMaskTestParam(32, 64, true),
+    WeightMaskTestParam(64, 16, true),    WeightMaskTestParam(64, 32, true),
+    WeightMaskTestParam(64, 64, true),    WeightMaskTestParam(64, 128, true),
+    WeightMaskTestParam(128, 64, true),   WeightMaskTestParam(128, 128, true),
+};
+
+using WeightMaskTest8bpp = WeightMaskTest<8>;
+
+TEST_P(WeightMaskTest8bpp, FixedValues) {
+  const int min = kCompoundPredictionRange[0][0];
+  const int max = kCompoundPredictionRange[0][1];
+  Test(1, true, min, min);
+  Test(1, true, min, max);
+  Test(1, true, max, min);
+  Test(1, true, max, max);
+}
+
+TEST_P(WeightMaskTest8bpp, RandomValues) { Test(1, false, -1, -1); }
+
+TEST_P(WeightMaskTest8bpp, DISABLED_Speed) {
+  Test(kNumSpeedTests, false, -1, -1);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, WeightMaskTest8bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WeightMaskTest8bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, WeightMaskTest8bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using WeightMaskTest10bpp = WeightMaskTest<10>;
+
+TEST_P(WeightMaskTest10bpp, FixedValues) {
+  const int min = kCompoundPredictionRange[1][0];
+  const int max = kCompoundPredictionRange[1][1];
+  Test(1, true, min, min);
+  Test(1, true, min, max);
+  Test(1, true, max, min);
+  Test(1, true, max, max);
+}
+
+TEST_P(WeightMaskTest10bpp, RandomValues) { Test(1, false, -1, -1); }
+
+TEST_P(WeightMaskTest10bpp, DISABLED_Speed) {
+  Test(kNumSpeedTests, false, -1, -1);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, WeightMaskTest10bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, WeightMaskTest10bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#endif
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, WeightMaskTest10bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using WeightMaskTest12bpp = WeightMaskTest<12>;
+
+TEST_P(WeightMaskTest12bpp, FixedValues) {
+  const int min = kCompoundPredictionRange[2][0];
+  const int max = kCompoundPredictionRange[2][1];
+  Test(1, true, min, min);
+  Test(1, true, min, max);
+  Test(1, true, max, min);
+  Test(1, true, max, max);
+}
+
+TEST_P(WeightMaskTest12bpp, RandomValues) { Test(1, false, -1, -1); }
+
+TEST_P(WeightMaskTest12bpp, DISABLED_Speed) {
+  Test(kNumSpeedTests, false, -1, -1);
+}
+
+INSTANTIATE_TEST_SUITE_P(C, WeightMaskTest12bpp,
+                         testing::ValuesIn(weight_mask_test_param));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/dsp/x86/common_avx2_test.cc b/src/dsp/x86/common_avx2_test.cc
new file mode 100644
index 0000000..2062683
--- /dev/null
+++ b/src/dsp/x86/common_avx2_test.cc
@@ -0,0 +1,67 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/x86/common_avx2.h"
+
+#include "gtest/gtest.h"
+
+#if LIBGAV1_TARGETING_AVX2
+
+#include <cstdint>
+
+#include "src/utils/common.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// Show that RightShiftWithRounding_S16() is equal to
+// RightShiftWithRounding() only for values less than or equal to
+// INT16_MAX - ((1 << bits) >> 1). In particular, if bits == 16, then
+// RightShiftWithRounding_S16() is equal to RightShiftWithRounding() only for
+// negative values.
+TEST(CommonDspTest, AVX2RightShiftWithRoundingS16) {
+  for (int bits = 0; bits < 16; ++bits) {
+    const int bias = (1 << bits) >> 1;
+    for (int32_t value = INT16_MIN; value <= INT16_MAX; ++value) {
+      const __m256i v_val_d = _mm256_set1_epi16(value);
+      const __m256i v_result_d = RightShiftWithRounding_S16(v_val_d, bits);
+      // Note _mm256_extract_epi16 is avoided for compatibility with Visual
+      // Studio < 2017.
+      const int16_t result =
+          _mm_extract_epi16(_mm256_extracti128_si256(v_result_d, 0), 0);
+      const int32_t expected = RightShiftWithRounding(value, bits);
+      if (value <= INT16_MAX - bias) {
+        EXPECT_EQ(result, expected) << "value: " << value << ", bits: " << bits;
+      } else {
+        EXPECT_EQ(expected, 1 << (15 - bits));
+        EXPECT_EQ(result, -expected)
+            << "value: " << value << ", bits: " << bits;
+      }
+    }
+  }
+}
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
+
+#else  // !LIBGAV1_TARGETING_AVX2
+
+TEST(CommonDspTest, AVX2) {
+  GTEST_SKIP() << "Build this module for x86(-64) with AVX2 enabled to enable "
+                  "the tests.";
+}
+
+#endif  // LIBGAV1_TARGETING_AVX2
diff --git a/src/dsp/x86/common_sse4_test.cc b/src/dsp/x86/common_sse4_test.cc
new file mode 100644
index 0000000..3288cfc
--- /dev/null
+++ b/src/dsp/x86/common_sse4_test.cc
@@ -0,0 +1,64 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/x86/common_sse4.h"
+
+#include "gtest/gtest.h"
+
+#if LIBGAV1_TARGETING_SSE4_1
+
+#include <cstdint>
+
+#include "src/utils/common.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace {
+
+// Show that RightShiftWithRounding_S16() is equal to
+// RightShiftWithRounding() only for values less than or equal to
+// INT16_MAX - ((1 << bits) >> 1). In particular, if bits == 16, then
+// RightShiftWithRounding_S16() is equal to RightShiftWithRounding() only for
+// negative values.
+TEST(CommonDspTest, SSE41RightShiftWithRoundingS16) {
+  for (int bits = 0; bits < 16; ++bits) {
+    const int bias = (1 << bits) >> 1;
+    for (int32_t value = INT16_MIN; value <= INT16_MAX; ++value) {
+      const __m128i v_val_d = _mm_set1_epi16(value);
+      const __m128i v_result_d = RightShiftWithRounding_S16(v_val_d, bits);
+      const int16_t result = _mm_extract_epi16(v_result_d, 0);
+      const int32_t expected = RightShiftWithRounding(value, bits);
+      if (value <= INT16_MAX - bias) {
+        EXPECT_EQ(result, expected) << "value: " << value << ", bits: " << bits;
+      } else {
+        EXPECT_EQ(expected, 1 << (15 - bits));
+        EXPECT_EQ(result, -expected)
+            << "value: " << value << ", bits: " << bits;
+      }
+    }
+  }
+}
+
+}  // namespace
+}  // namespace dsp
+}  // namespace libgav1
+
+#else  // !LIBGAV1_TARGETING_SSE4_1
+
+TEST(CommonDspTest, SSE41) {
+  GTEST_SKIP() << "Build this module for x86(-64) with SSE4 enabled to enable "
+                  "the tests.";
+}
+
+#endif  // LIBGAV1_TARGETING_SSE4_1
diff --git a/src/film_grain_test.cc b/src/film_grain_test.cc
new file mode 100644
index 0000000..d5854e0
--- /dev/null
+++ b/src/film_grain_test.cc
@@ -0,0 +1,2687 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dsp/film_grain.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <new>
+#include <string>
+#include <tuple>
+#include <type_traits>
+
+#include "absl/strings/match.h"
+#include "absl/strings/str_format.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/common.h"
+#include "src/dsp/dsp.h"
+#include "src/dsp/film_grain_common.h"
+#include "src/film_grain.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "src/utils/threadpool.h"
+#include "src/utils/types.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace dsp {
+namespace film_grain {
+namespace {
+
+constexpr int kNumSpeedTests = 50;
+constexpr int kNumFilmGrainTestParams = 10;
+constexpr size_t kLumaBlockSize = kLumaWidth * kLumaHeight;
+constexpr size_t kChromaBlockSize = kMaxChromaWidth * kMaxChromaHeight;
+// Dimensions for unit tests concerning applying grain to the whole frame.
+constexpr size_t kNumTestStripes = 64;
+constexpr int kNoiseStripeHeight = 34;
+constexpr size_t kFrameWidth = 1921;
+constexpr size_t kFrameHeight = (kNumTestStripes - 1) * 32 + 1;
+
+/*
+  The film grain parameters for 10 frames were generated with the following
+  command line:
+  aomenc --end-usage=q --cq-level=20 --cpu-used=8 -w 1920 -h 1080 \
+    --denoise-noise-level=50 --ivf breaking_bad_21m23s_10frames.1920_1080.yuv \
+    -o breaking_bad_21m23s_10frames.1920_1080.noise50.ivf
+*/
+constexpr FilmGrainParams kFilmGrainParams[10] = {
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/8,
+     /*num_v_points=*/8,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 121, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{71, 71, 91, 99, 98, 100, 100, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 27, 40, 54, 67, 94, 255, 0, 0},
+     /*point_u_scaling=*/{37, 37, 43, 48, 48, 50, 51, 51, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 107, 255, 0, 0},
+     /*point_v_scaling=*/{48, 48, 43, 33, 32, 33, 34, 34, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  10,  3, -2, 1,   -4,
+                                  5,   -1,  -25, -13, 3, -1, 0,   7,
+                                  -20, 103, 26,  -2,  1, 14, -49, 117},
+     /*auto_regression_coeff_u=*/{-2,  1,  -3, 4,   -4, 0,  3,   5,  -5,
+                                  -17, 17, 0,  -10, -5, -3, -30, 14, 70,
+                                  29,  9,  -2, -10, 50, 71, -11},
+     /*auto_regression_coeff_v=*/{3,   -2, -7, 6,   -7, -8, 3,   1,  -12,
+                                  -15, 28, 5,  -11, -2, -7, -27, 32, 62,
+                                  31,  18, -2, -6,  61, 43, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/7391,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/8,
+     /*num_u_points=*/7,
+     /*num_v_points=*/8,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 94, 134, 255, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 91, 99, 97, 100, 102, 102, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 134, 255, 0, 0, 0},
+     /*point_u_scaling=*/{38, 38, 50, 49, 51, 53, 53, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 255, 0, 0},
+     /*point_v_scaling=*/{50, 50, 45, 34, 33, 35, 37, 37, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  10,  3,  -1, 1,   -3,
+                                  3,   1,   -27, -12, 2,  -1, 1,   7,
+                                  -17, 100, 27,  0,   -1, 13, -50, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 2,   5,  -3,
+                                  -16, 16, -2, -10, -2, -1, -31, 14, 70,
+                                  29,  9,  -1, -10, 47, 70, -11},
+     /*auto_regression_coeff_v=*/{1,   0,  -5, 5,   -6, -6, 2,   1,  -10,
+                                  -14, 26, 4,  -10, -3, -5, -26, 29, 63,
+                                  31,  17, -1, -6,  55, 47, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/10772,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/8,
+     /*num_u_points=*/7,
+     /*num_v_points=*/8,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 94, 134, 255, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{71, 71, 91, 99, 98, 101, 103, 103, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 81, 107, 255, 0, 0, 0},
+     /*point_u_scaling=*/{37, 37, 49, 48, 51, 52, 52, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 255, 0, 0},
+     /*point_v_scaling=*/{49, 49, 44, 34, 32, 34, 36, 36, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{1,   -2,  -2,  10,  3, -1, 1,   -4,
+                                  4,   1,   -26, -12, 2, -1, 1,   7,
+                                  -18, 101, 26,  -1,  0, 13, -49, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -3, 4,   -3, -1, 2,   5,  -4,
+                                  -16, 17, -2, -10, -3, -2, -31, 15, 70,
+                                  28,  9,  -1, -10, 48, 70, -11},
+     /*auto_regression_coeff_v=*/{1,   -1, -6, 5,   -6, -7, 2,   2,  -11,
+                                  -14, 27, 5,  -11, -3, -6, -26, 30, 62,
+                                  30,  18, -2, -6,  58, 45, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/14153,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/5,
+     /*num_v_points=*/7,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 121, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{71, 71, 90, 99, 98, 100, 100, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 107, 255, 0, 0, 0, 0, 0},
+     /*point_u_scaling=*/{37, 37, 48, 51, 51, 0, 0, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 94, 255, 0, 0, 0},
+     /*point_v_scaling=*/{49, 49, 43, 33, 32, 34, 34, 0, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  10,  3, -1, 1,   -4,
+                                  6,   0,   -26, -13, 3, -1, 1,   6,
+                                  -20, 103, 26,  -2,  1, 13, -48, 117},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 4,   -4, -1, 2,   5,  -5,
+                                  -16, 18, -1, -10, -3, -2, -30, 16, 69,
+                                  28,  9,  -2, -10, 50, 68, -11},
+     /*auto_regression_coeff_v=*/{2,   -1, -6, 5,   -6, -7, 2,   2,  -11,
+                                  -15, 29, 4,  -10, -3, -6, -26, 30, 62,
+                                  31,  18, -3, -6,  59, 45, 3},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/17534,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/8,
+     /*num_u_points=*/7,
+     /*num_v_points=*/7,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 94, 134, 255, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{71, 71, 91, 99, 98, 101, 103, 103, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 81, 107, 255, 0, 0, 0},
+     /*point_u_scaling=*/{37, 37, 49, 49, 52, 53, 53, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 94, 255, 0, 0, 0},
+     /*point_v_scaling=*/{50, 50, 44, 34, 33, 36, 37, 0, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  10,  3, -1, 1,   -4,
+                                  3,   1,   -26, -12, 2, -1, 1,   7,
+                                  -17, 101, 26,  0,   0, 13, -50, 116},
+     /*auto_regression_coeff_u=*/{-2,  1,  -2, 3,   -3, -1, 2,   5,  -4,
+                                  -16, 16, -2, -10, -3, -1, -31, 14, 70,
+                                  28,  9,  -1, -10, 48, 70, -11},
+     /*auto_regression_coeff_v=*/{1,   0,  -5, 5,   -6, -6, 2,   2,  -10,
+                                  -14, 26, 4,  -10, -3, -5, -26, 29, 63,
+                                  30,  17, -1, -6,  56, 47, 3},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/20915,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/7,
+     /*num_v_points=*/7,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 134, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 91, 99, 97, 101, 101, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 107, 255, 0, 0, 0},
+     /*point_u_scaling=*/{38, 38, 51, 50, 52, 53, 54, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 94, 255, 0, 0, 0},
+     /*point_v_scaling=*/{51, 51, 45, 35, 33, 36, 36, 0, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  9,   3,  -1, 1,   -3,
+                                  2,   2,   -27, -12, 2,  0,  1,   7,
+                                  -16, 100, 27,  0,   -1, 13, -51, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 1,   4,  -2,
+                                  -17, 14, -3, -10, -2, 0,  -31, 14, 71,
+                                  29,  8,  -2, -10, 45, 71, -11},
+     /*auto_regression_coeff_v=*/{0,   -1, -5, 4,   -6, -5, 2,   1,  -9,
+                                  -14, 24, 3,  -10, -3, -4, -25, 29, 63,
+                                  31,  16, -1, -7,  54, 48, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/24296,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/7,
+     /*num_v_points=*/8,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 134, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 91, 99, 97, 101, 101, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 134, 255, 0, 0, 0},
+     /*point_u_scaling=*/{38, 38, 50, 50, 51, 53, 53, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 255, 0, 0},
+     /*point_v_scaling=*/{50, 50, 45, 34, 33, 35, 36, 36, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{2,   -2,  -2,  10,  3,  -1, 1,   -3,
+                                  3,   2,   -27, -12, 2,  0,  1,   7,
+                                  -17, 100, 27,  0,   -1, 13, -51, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 1,   5,  -3,
+                                  -16, 15, -2, -10, -2, -1, -31, 14, 70,
+                                  29,  8,  -1, -10, 46, 71, -11},
+     /*auto_regression_coeff_v=*/{1,   0,  -5, 5,   -6, -5, 2,   1,  -9,
+                                  -14, 25, 4,  -10, -3, -5, -25, 29, 63,
+                                  31,  17, -1, -7,  55, 47, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/27677,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/7,
+     /*num_v_points=*/8,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 121, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 92, 99, 97, 101, 101, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 174, 255, 0, 0, 0},
+     /*point_u_scaling=*/{38, 38, 51, 50, 52, 54, 54, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 255, 0, 0},
+     /*point_v_scaling=*/{51, 51, 46, 35, 33, 35, 37, 37, 0, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{1,   -1, -2,  9,   3,  -1, 1,   -3,
+                                  2,   2,  -28, -12, 2,  0,  1,   8,
+                                  -16, 99, 27,  0,   -1, 13, -51, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 2,   4,  -2,
+                                  -16, 14, -3, -10, -2, 0,  -31, 13, 71,
+                                  29,  8,  -2, -11, 44, 72, -11},
+     /*auto_regression_coeff_v=*/{0,   -1, -5, 4,   -6, -4, 2,   1,  -9,
+                                  -13, 23, 3,  -10, -3, -4, -25, 28, 63,
+                                  32,  16, -1, -7,  54, 49, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/31058,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/7,
+     /*num_v_points=*/9,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 121, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 92, 99, 98, 100, 98, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 228, 255, 0, 0, 0},
+     /*point_u_scaling=*/{38, 38, 51, 51, 52, 54, 54, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 201, 255, 0},
+     /*point_v_scaling=*/{51, 51, 46, 35, 34, 35, 37, 37, 37, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{1,   -1, -2,  9,   3,  -1, 1,   -3,
+                                  2,   2,  -28, -12, 2,  0,  1,   8,
+                                  -16, 99, 27,  0,   -1, 13, -52, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 1,   4,  -2,
+                                  -16, 13, -3, -10, -2, 0,  -31, 13, 71,
+                                  29,  8,  -2, -11, 44, 72, -11},
+     /*auto_regression_coeff_v=*/{0,   -1, -5, 4,   -6, -4, 2,   2,  -8,
+                                  -13, 23, 3,  -10, -3, -4, -25, 28, 63,
+                                  32,  16, -1, -7,  54, 49, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/34439,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0},
+    {/*apply_grain=*/true,
+     /*update_grain=*/true,
+     /*chroma_scaling_from_luma=*/false,
+     /*overlap_flag=*/true,
+     /*clip_to_restricted_range=*/false,
+     /*num_y_points=*/7,
+     /*num_u_points=*/7,
+     /*num_v_points=*/9,
+     /*point_y_value=*/{0, 13, 27, 40, 54, 121, 255, 0, 0, 0, 0, 0, 0, 0},
+     /*point_y_scaling=*/{72, 72, 92, 99, 98, 99, 95, 0, 0, 0, 0, 0, 0, 0},
+     /*point_u_value=*/{0, 13, 40, 54, 67, 228, 255, 0, 0, 0},
+     /*point_u_scaling=*/{39, 39, 51, 51, 52, 54, 54, 0, 0, 0},
+     /*point_v_value=*/{0, 13, 27, 40, 54, 67, 121, 201, 255, 0},
+     /*point_v_scaling=*/{51, 51, 46, 35, 34, 35, 36, 35, 35, 0},
+     /*chroma_scaling=*/11,
+     /*auto_regression_coeff_lag=*/3,
+     /*auto_regression_coeff_y=*/{1,   -1, -2,  9,   3,  -1, 1,   -3,
+                                  2,   2,  -28, -11, 2,  0,  1,   8,
+                                  -16, 99, 27,  0,   -1, 13, -52, 116},
+     /*auto_regression_coeff_u=*/{-3,  1,  -2, 3,   -3, -1, 1,   4,  -2,
+                                  -16, 13, -3, -10, -2, 0,  -30, 13, 71,
+                                  29,  8,  -2, -10, 43, 72, -11},
+     /*auto_regression_coeff_v=*/{0,   -1, -5, 3,   -6, -4, 2,   2,  -8,
+                                  -13, 23, 3,  -10, -3, -4, -25, 28, 64,
+                                  32,  16, -1, -7,  53, 49, 2},
+     /*auto_regression_shift=*/8,
+     /*grain_seed=*/37820,
+     /*reference_index=*/0,
+     /*grain_scale_shift=*/0,
+     /*u_multiplier=*/0,
+     /*u_luma_multiplier=*/64,
+     /*u_offset=*/0,
+     /*v_multiplier=*/0,
+     /*v_luma_multiplier=*/64,
+     /*v_offset=*/0}};
+
+const char* GetTestDigestLuma(int bitdepth, int param_index) {
+  static const char* const kTestDigestsLuma8bpp[10] = {
+      "80da8e849110a10c0a73f9dec0d9a2fb", "54352f02aeda541e17a4c2d208897e2b",
+      "2ad9021124c82aca3e7c9517d00d1236", "f6c5f64513925b09ceba31e92511f8a1",
+      "46c6006578c68c3c8619f7a389c7de45", "fcddbd27545254dc50f1c333c8b7e313",
+      "c6d4dc181bf7f2f93ae099b836685151", "2949ef836748271195914fef9acf4e46",
+      "524e79bb87ed550e123d00a61df94381", "182222470d7b7a80017521d0261e4474",
+  };
+  static const char* const kTestDigestsLuma10bpp[10] = {
+      "27a49a2131fb6d4dd4b8c34da1b7642e", "4ea9134f6831dd398545c85b2a68e31f",
+      "4e12232a18a2b06e958d7ab6b953faad", "0ede12864ddaced2d8062ffa4225ce24",
+      "5fee492c4a430b2417a64aa4920b69e9", "39af842a3f9370d796e8ef047c0c42a8",
+      "0efbad5f9dc07391ad243232b8df1787", "2bd41882cd82960019aa2b87d5fb1fbc",
+      "1c66629c0c4e7b6f9b0a7a6944fbad50", "2c633a50ead62f8e844a409545f46244",
+  };
+  static const char* const kTestDigestsLuma12bpp[10] = {
+      "1dc9b38a93454a85eb924f25346ae369", "5f9d311ee5384a5a902f8e2d1297319e",
+      "cf1a35878720564c7a741f91eef66565", "47a0608fe0f6f7ccae42a5ca05783cbf",
+      "dbc28da0178e3c18a036c3f2203c300f", "04911d2074e3252119ee2d80426b8c01",
+      "df19ab8103c40b726c842ccf7772208b", "39276967eb16710d98f82068c3eeba41",
+      "b83100f18abb2062d9c9969f07182b86", "b39a69515491329698cf66f6d4fa371f",
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsLuma8bpp[param_index];
+    case 10:
+      return kTestDigestsLuma10bpp[param_index];
+    case 12:
+      return kTestDigestsLuma12bpp[param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetTestDigestChromaU(int bitdepth, int param_index) {
+  static const char* const kTestDigestsChromaU8bpp[10] = {
+      "e56b7bbe9f39bf987770b18aeca59514", "d0b3fd3cf2901dae31b73f20c510d83e",
+      "800c01d58d9fb72136d21ec2bb07899a", "4cd0badba679e8edbcd60a931fce49a1",
+      "cabec236cc17f91f3f08d8cde867aa72", "380a2205cf2d40c6a27152585f61a3b0",
+      "3813526234dc7f90f80f6684772c729a", "97a43a73066d88f9cbd915d56fc9c196",
+      "5b70b27a43dd63b03e23aecd3a935071", "d5cc98685582ffd47a41a97d2e377ac8",
+  };
+  static const char* const kTestDigestsChromaU10bpp[10] = {
+      "9a6d0369ba86317598e65913276dae6d", "2512bdc4c88f21f8185b040b7752d1db",
+      "1e86b779ce6555fcf5bd0ade2af67e73", "5ad463a354ffce522c52b616fb122024",
+      "290d53c22c2143b0882acb887da3fdf1", "54622407d865371d7e70bbf29fdda626",
+      "be306c6a94c55dbd9ef514f0ad4a0011", "904602329b0dec352b3b177b0a2554d2",
+      "58afc9497d968c67fdf2c0cf23b33aa3", "74fee7be6f62724bf901fdd04a733b46",
+  };
+  static const char* const kTestDigestsChromaU12bpp[10] = {
+      "846d608050fe7c19d6cabe2d53cb7821", "2caf4665a26aad50f68497e4b1326417",
+      "ce40f0f8f8c207c7c985464c812fea33", "820de51d07a21da5c00833bab546f1fa",
+      "5e7bedd8933cd274af03babb4dbb94dd", "d137cf584eabea86387460a6d3f62bfe",
+      "f206e0c6ed35b3ab35c6ff37e151e963", "55d87981b7044df225b3b5935185449b",
+      "6a655c8bf4df6af0e80ae6d004a73a25", "6234ae36076cc77161af6e6e3c04449a",
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsChromaU8bpp[param_index];
+    case 10:
+      return kTestDigestsChromaU10bpp[param_index];
+    case 12:
+      return kTestDigestsChromaU12bpp[param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetTestDigestChromaV(int bitdepth, int param_index) {
+  static const char* const kTestDigestsChromaV8bpp[10] = {
+      "7205ed6c07ed27b7b52d871e0559b8fa", "fad033b1482dba0ed2d450b461fa310e",
+      "6bb39798ec6a0f7bda0b0fcb0a555734", "08c19856e10123ae520ccfc63e2fbe7b",
+      "a7695a6b69fba740a50310dfa6cf1c00", "ac2eac2d13fc5b21c4f2995d5abe14b9",
+      "be35cb30062db628a9e1304fca8b75dc", "f5bfc7a910c76bcd5b32c40772170879",
+      "aca07b37d63f978d76df5cd75d0cea5e", "107c7c56d4ec21f346a1a02206301b0d",
+  };
+  static const char* const kTestDigestsChromaV10bpp[10] = {
+      "910724a77710996c90e272f1c1e9ff8e", "d293f861580770a89f1e266931a012ad",
+      "9e4f0c85fb533e51238586f9c3e68b6e", "a5ff4478d9eeb2168262c2e955e17a4f",
+      "fba6b1e8f28e4e90c836d41f28a0c154", "50b9a93f9a1f3845e6903bff9270a3e6",
+      "7b1624c3543badf5fadaee4d1e602e6b", "3be074e4ca0eec5770748b15661aaadd",
+      "639197401032f272d6c30666a2d08f43", "28075dd34246bf9d5e6197b1944f646a",
+  };
+  static const char* const kTestDigestsChromaV12bpp[10] = {
+      "4957ec919c20707d594fa5c2138c2550", "3f07c65bfb42c81768b1f5ad9611d1ce",
+      "665d9547171c99faba95ac81a35c9a0c", "1b5d032e0cefdb4041ad51796de8a45e",
+      "18fa974579a4f1ff8cd7df664fc339d5", "2ffaa4f143495ff73c06a580a97b6321",
+      "4fd1f562bc47a68dbfaf7c566c7c4da6", "4d37c80c9caf110c1d3d20bd1a1875b3",
+      "8ea29759640962613166dc5154837d14", "5ca4c10f42d0906c72ebee90fae6ce7d",
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsChromaV8bpp[param_index];
+    case 10:
+      return kTestDigestsChromaV10bpp[param_index];
+    case 12:
+      return kTestDigestsChromaV12bpp[param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetARTestDigestLuma(int bitdepth, int coeff_lag, int param_index) {
+  static const char* const kTestDigestsLuma8bpp[3][kNumFilmGrainTestParams] = {
+      {"a835127918f93478b45f1ba4d20d81bd", "a835127918f93478b45f1ba4d20d81bd",
+       "e5db4da626e214bb17bcc7ecffa76303", "a835127918f93478b45f1ba4d20d81bd",
+       "a835127918f93478b45f1ba4d20d81bd", "e5db4da626e214bb17bcc7ecffa76303",
+       "a835127918f93478b45f1ba4d20d81bd", "1da62b7233de502123a18546b6c97da2",
+       "1da62b7233de502123a18546b6c97da2", "1da62b7233de502123a18546b6c97da2"},
+      {"11464b880de3ecd6e6189c5c4e7f9b28", "dfe411762e283b5f49bece02ec200951",
+       "5c534d92afdf0a5b53dbe4fe7271929c", "2e1a68a18aca96c31320ba7ceab59be9",
+       "584c0323e6b276cb9acb1a294d462d58", "9571eb8f1cbaa96ea3bf64a820a8d9f0",
+       "305285ff0df87aba3c59e3fc0818697d", "0066d35c8818cf20230114dcd3765a4d",
+       "0066d35c8818cf20230114dcd3765a4d", "16d61b046084ef2636eedc5a737cb6f6"},
+      {"0c9e2cf1b6c3cad0f7668026e8ea0516", "7d094855292d0eded9e0d1b5bab1990b",
+       "fbf28860a5f1285dcc6725a45256a86a", "dccb906904160ccabbd2c9a7797a4bf9",
+       "46f645e17f08a3260b1ae70284e5c5b8", "124fdc90bed11a7320a0cbdee8b94400",
+       "8d2978651dddeaef6282191fa146f0a0", "28b4d5aa33f05b3fb7f9323a11936bdc",
+       "6a8ea684f6736a069e3612d1af6391a8", "2781ea40a63704dbfeb3a1ac5db6f2fc"},
+  };
+
+  static const char* const kTestDigestsLuma10bpp[3][kNumFilmGrainTestParams] = {
+      {"5e6bc8444ece2d38420f51d82238d812", "5e6bc8444ece2d38420f51d82238d812",
+       "2bfaec768794af33d60a9771f971f68d", "5e6bc8444ece2d38420f51d82238d812",
+       "5e6bc8444ece2d38420f51d82238d812", "c880807a368c4e82c23bea6f035ad23f",
+       "5e6bc8444ece2d38420f51d82238d812", "c576667da5286183ec3aab9a76f53a2e",
+       "c576667da5286183ec3aab9a76f53a2e", "c576667da5286183ec3aab9a76f53a2e"},
+      {"095c2dd4d4d52aff9696df9bfdb70062", "983d14afa497060792d472a449a380c7",
+       "c5fdc0f7c594b2b36132cec6f45a79bd", "acff232ac5597c1712213150552281d1",
+       "4dd7341923b1d260092853553b6b6246", "0ca8afd71a4f564ea1ce69c4af14e9ab",
+       "9bc7565e5359d09194fcee28e4bf7b94", "6fea7805458b9d149f238a30e2dc3f13",
+       "6fea7805458b9d149f238a30e2dc3f13", "681dff5fc7a7244ba4e4a582ca7ecb14"},
+      {"cb99352c9c6300e7e825188bb4adaee0", "7e40674de0209bd72f8e9c6e39ee6f7c",
+       "3e475572f6b4ecbb2730fd16751ad7ed", "e6e4c63abc9cb112d9d1f23886cd1415",
+       "1a1c953b175c105c604902877e2bab18", "380a53072530223d4ee622e014ee4bdb",
+       "6137394ea1172fb7ea0cbac237ff1703", "85ab0c813e46f97cb9f42542f44c01ad",
+       "68c8ac462f0e28cb35402c538bee32f1", "0038502ffa4760c8feb6f9abd4de7250"},
+  };
+
+  static const char* const kTestDigestsLuma12bpp[3][kNumFilmGrainTestParams] = {
+      {"d618bbb0e337969c91b1805f39561520", "d618bbb0e337969c91b1805f39561520",
+       "678f6e911591daf9eca4e305dabdb2b3", "d618bbb0e337969c91b1805f39561520",
+       "d618bbb0e337969c91b1805f39561520", "3b26f49612fd587c7360790d40adb5de",
+       "d618bbb0e337969c91b1805f39561520", "33f77d3ff50cfc64c6bc9a896b567377",
+       "33f77d3ff50cfc64c6bc9a896b567377", "33f77d3ff50cfc64c6bc9a896b567377"},
+      {"362fd67050fb7abaf57c43a92d993423", "e014ae0eb9e697281015c38905cc46ef",
+       "82b867e57151dc08afba31eccf5ccf69", "a94ba736cdce7bfa0b550285f59e47a9",
+       "3f1b0b7dd3b10e322254d35e4e185b7c", "7929708e5f017d58c53513cb79b35fda",
+       "6d26d31a091cbe642a7070933bd7de5a", "dc29ac40a994c0a760bfbad0bfc15b3a",
+       "dc29ac40a994c0a760bfbad0bfc15b3a", "399b919db5190a5311ce8d166580827b"},
+      {"6116d1f569f5b568eca4dc1fbf255086", "7e9cf31ea74e8ea99ffd12094ce6cd05",
+       "bb982c4c39e82a333d744defd16f4388", "7c6e584b082dc6b97ed0d967def3993f",
+       "fb234695353058f03c8e128f2f8de130", "9218c6ca67bf6a9237f98aa1ce7acdfd",
+       "d1fb834bbb388ed066c5cbc1c79b5bdf", "d6f630daedc08216fcea12012e7408b5",
+       "dd7fe49299e6f113a98debc7411c8db8", "8b89e45a5101a28c24209ae119eafeb8"},
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsLuma8bpp[coeff_lag - 1][param_index];
+    case 10:
+      return kTestDigestsLuma10bpp[coeff_lag - 1][param_index];
+    case 12:
+      return kTestDigestsLuma12bpp[coeff_lag - 1][param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetARTestDigestChromaU(int bitdepth, int coeff_lag,
+                                   int subsampling_x, int subsampling_y) {
+  static const char* const kTestDigestsChromaU8bpp[12] = {
+      "11ced66de0eaf55c1ff9bad18d7b8ed7", "0c3b77345dd4ab0915ef53693ab93ce4",
+      "b0645044ba080b3ceb8f299e269377d6", "50590ad5d895f0b4bc6694d878e9cd32",
+      "85e1bf3741100135062f5b4abfe7639b", "76955b70dde61ca5c7d079c501b90906",
+      "3f0995e1397fd9efd9fc46b67f7796b3", "0a0d6c3e4e1649eb101395bc97943a07",
+      "1878855ed8db600ccae1d39abac52ec6", "13ab2b28320ed3ac2b820f08fdfd424d",
+      "f3e95544a86ead5387e3dc4e043fd0f0", "ff8f5d2d97a6689e16a7e4f482f69f0b",
+  };
+
+  static const char* const kTestDigestsChromaU10bpp[12] = {
+      "707f2aa5aa7e77bc6e83ab08287d748d", "0bcf40c7fead9ac3a5d71b4cc1e21549",
+      "0c1df27053e5da7cf1276a122a8f4e8b", "782962f7425eb38923a4f87e7ab319d9",
+      "b4a709ae5967afef55530b9ea8ef0062", "70a971a0b9bf06212d510b396f0f9095",
+      "d033b89d6e31f8b13c83d94c840b7d54", "40bbe804bf3f90cee667d3b275e3c964",
+      "90bb2b9d518b945adcfd1b1807f7d170", "4bc34aa157fe5ad4270c611afa75e878",
+      "e2688d7286cd43fe0a3ea734d2ad0f77", "853193c4981bd882912171061327bdf2",
+  };
+
+  static const char* const kTestDigestsChromaU12bpp[12] = {
+      "04c23b01d01c0e3f3247f3741581b383", "9f8ea1d66e44f6fe93d765ce56b2b0f3",
+      "5dda44b128d6c244963f1e8e17cc1d22", "9dd0a79dd2f772310a95762d445bface",
+      "0dbd40d930e4873d72ea72b9e3d62440", "d7d83c207c6b435a164206d5f457931f",
+      "e8d04f6e63ed63838adff965275a1ff1", "fc09a903e941fcff8bad67a84f705775",
+      "9cd706606a2aa40d0957547756f7abd9", "258b37e7b8f48db77dac7ea24073fe69",
+      "80149b8bb05308da09c1383d8b79d3da", "e993f3bffae53204a1942feb1af42074",
+  };
+
+  assert(!(subsampling_x == 0 && subsampling_y == 1));
+  const int base_index = 3 * coeff_lag + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsChromaU8bpp[base_index];
+    case 10:
+      return kTestDigestsChromaU10bpp[base_index];
+    case 12:
+      return kTestDigestsChromaU12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetARTestDigestChromaV(int bitdepth, int coeff_lag,
+                                   int subsampling_x, int subsampling_y) {
+  static const char* const kTestDigestsChromaV8bpp[12] = {
+      "5c2179f3d93be0a0da75d2bb90347c2f", "79b883847d7eaa7890e1d633b8e34353",
+      "90ade818e55808e8cf58c11debb5ddd1", "1d0f2a14bc4df2b2a1abaf8137029f92",
+      "ac753a57ade140dccb50c14f941ae1fc", "d24ab497558f6896f08dc17bcc3c50c1",
+      "3d74436c63920022a95c85b234db4e33", "061c2d53ed84c830f454e395c362cb16",
+      "05d24869d7fb952e332457a114c8b9b7", "fcee31b87a2ada8028c2a975e094856a",
+      "c019e2c475737abcf9c2b2a52845c646", "9cd994baa7021f8bdf1d1c468c1c8e9c",
+  };
+
+  static const char* const kTestDigestsChromaV10bpp[12] = {
+      "bc9e44454a05cac8571c15af5b720e79", "f0374436698d94e879c03331b1f30df4",
+      "4580dd009abd6eeed59485057c55f63e", "7d1f7aecd45302bb461f4467f2770f72",
+      "1f0d003fce6c5fedc147c6112813f43b", "4771a45c2c1a04c375400619d5536035",
+      "df9cf619a78907c0f6e58bc13d7d5546", "dd3715ce65d905f30070a36977c818e0",
+      "32de5800f76e34c128a1d89146b4010b", "db9d7c70c3f69feb68fae04398efc773",
+      "d3d0912e3fdb956fef416a010bd7b4c2", "a2fca8abd9fd38d2eef3c4495d9eff78",
+  };
+
+  static const char* const kTestDigestsChromaV12bpp[12] = {
+      "0d1890335f4464167de22353678ca9c6", "9e6830aba73139407196f1c811f910bc",
+      "6018f2fb76bd648bef0262471cfeba5c", "78e1ae1b790d709cdb8997621cf0fde3",
+      "5b44ae281d7f9db2f17aa3c24b4741dd", "f931d16991669cb16721de87da9b8067",
+      "5580f2aed349d9cabdafb9fc25a57b1c", "86918cd78bf95e6d4405dd050f5890b8",
+      "13c8b314eeebe35fa60b703d94e1b2c1", "13c6fb75cab3f42e0d4ca31e4d068b0e",
+      "bb9ca0bd6f8cd67e44c8ac2803abf5a5", "0da4ea711ffe557bb66577392b6f148b",
+  };
+
+  assert(!(subsampling_x == 0 && subsampling_y == 1));
+  const int base_index = 3 * coeff_lag + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsChromaV8bpp[base_index];
+    case 10:
+      return kTestDigestsChromaV10bpp[base_index];
+    case 12:
+      return kTestDigestsChromaV12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetGrainGenerationTestDigestLuma(int bitdepth, int param_index) {
+  static const char* const kTestDigestsLuma8bpp[kNumFilmGrainTestParams] = {
+      "c48babd99e5cfcbaa13d8b6e0c12e644", "da4b971d2de19b709e2bc98d2e50caf3",
+      "96c72faac19a79c138afeea8b8ae8c7a", "90a2b9c8304a44d14e83ca51bfd2fe8a",
+      "72bd3aa85c17850acb430afb4183bf1a", "a0acf76349b9efbc9181fc31153d9ef6",
+      "6da74dd631a4ec8b9372c0bbec22e246", "6e11fa230f0e5fbb13084255c22cabf9",
+      "be1d257b762f9880d81680e9325932a2", "37e302075af8130b371de4430e8a22cf",
+  };
+
+  static const char* const kTestDigestsLuma10bpp[kNumFilmGrainTestParams] = {
+      "0a40fd2f261095a6154584a531328142", "9d0c8173a94a0514c769e94b6f254030",
+      "7894e959fdd5545895412e1512c9352d", "6802cad2748cf6db7f66f53807ee46ab",
+      "ea24e962b98351c3d929a8ae41e320e2", "b333dc944274a3a094073889ca6e11d6",
+      "7211d7ac0ff7d11b5ef1538c0d98f43d", "ef9f9cbc101a07da7bfa62637130e331",
+      "85a122e32648fde84b883a1f98947c60", "dee656e3791138285bc5b71e3491a177",
+  };
+
+  static const char* const kTestDigestsLuma12bpp[kNumFilmGrainTestParams] = {
+      "ae359794b5340d073d597117046886ac", "4d4ad3908b4fb0f248a0086537dd6b1e",
+      "672a97e15180cbeeaf76d763992c9f23", "739124d10d16e00a158e833ea92107bc",
+      "4c38c738ff7ffc50adaa4474584d3aae", "ca05ba7e51000a7d10e5cbb2101bbd86",
+      "e207022b916bf03a76ac8742af29853d", "7454bf1859149237ff74f1161156c857",
+      "10fc2a16e663bbc305255b0883cfcd45", "4228abff6899bb33839b579288ab29fe",
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigestsLuma8bpp[param_index];
+    case 10:
+      return kTestDigestsLuma10bpp[param_index];
+    case 12:
+      return kTestDigestsLuma12bpp[param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetConstructStripesTestDigest(int bitdepth, int overlap_flag,
+                                          int subsampling_x,
+                                          int subsampling_y) {
+  static const char* const kTestDigests8bpp[6] = {
+      "cd14aaa6fc1728290fa75772730a2155", "13ad4551feadccc3a3a9bd5e25878d2a",
+      "ed6ad9532c96ef0d79ff3228c89a429f", "82f307a7f5fc3308c3ebe268b5169e70",
+      "aed793d525b85349a8c2eb6d40e93969", "311c3deb727621a7d4f18e8defb65de7",
+  };
+
+  static const char* const kTestDigests10bpp[6] = {
+      "4fe2fa1e428737de3595be3a097d0203", "80568c3c3b53bdbbd03b820179092dcd",
+      "bc7b73099961a0739c36e027d6d09ea1", "e5331364e5146a6327fd94e1467f59a3",
+      "125bf18b7787e8f0792ea12f9210de0d", "21cf98cbce17eca77dc150cc9be0e0a0",
+  };
+
+  static const char* const kTestDigests12bpp[6] = {
+      "57f8e17078b6e8935252e918a2562636", "556a7b294a99bf1163b7166b4f68357e",
+      "249bee5572cd7d1cc07182c97adc4ba7", "9bf43ae1998c2a5b2e5f4d8236b58747",
+      "477c08fa26499936e5bb03bde097633e", "fe64b7166ff87ea0711ae4f519cadd59",
+  };
+
+  const int base_index = 3 * overlap_flag + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigests8bpp[base_index];
+    case 10:
+      return kTestDigests10bpp[base_index];
+    case 12:
+      return kTestDigests12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetConstructImageTestDigest(int bitdepth, int overlap_flag,
+                                        int subsampling_x, int subsampling_y) {
+  static const char* const kTestDigests8bpp[6] = {
+      "17030fc692e685557a3717f9334af7e8", "d16ea46147183cd7bc36bcfc2f936a5b",
+      "68152958540dbec885f71e3bcd7aa088", "bb43b420f05a122eb4780aca06055ab1",
+      "87567b04fbdf64f391258c0742de266b", "ce87d556048b3de32570faf6729f4010",
+  };
+
+  static const char* const kTestDigests10bpp[6] = {
+      "5b31b29a5e22126a9bf8cd6a01645777", "2bb94a25164117f2ab18dae18e2c6577",
+      "27e57a4ed6f0c9fe0a763a03f44805e8", "481642ab0b07437b76b169aa4eb82123",
+      "656a9ef056b04565bec9ca7e0873c408", "a70fff81ab28d02d99dd4f142699ba39",
+  };
+
+  static const char* const kTestDigests12bpp[6] = {
+      "146f7ceadaf77e7a3c41e191a58c1d3c", "de18526db39630936733e687cdca189e",
+      "165c96ff63bf3136505ab1d239f7ceae", "a102636662547f84e5f6fb6c3e4ef959",
+      "4cb073fcc783c158a95c0b1ce0d27e9f", "3a734c71d4325a7da53e2a6e00f81647",
+  };
+
+  const int base_index = 3 * overlap_flag + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigests8bpp[base_index];
+    case 10:
+      return kTestDigests10bpp[base_index];
+    case 12:
+      return kTestDigests12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetScalingInitTestDigest(int param_index, int bitdepth) {
+  static const char* const kTestDigests8bpp[kNumFilmGrainTestParams] = {
+      "315202ca3bf9c46eac8605e89baffd2a", "640f6408702b07ab7e832e7326cce56f",
+      "f75ee83e3912a3f25949e852d67326cf", "211223f5d6a4b42a8e3c662f921b71c0",
+      "f75ee83e3912a3f25949e852d67326cf", "e7a1de8c5a2cac2145c586ecf1f9051c",
+      "e7a1de8c5a2cac2145c586ecf1f9051c", "276fe5e3b30b2db2a9ff798eb6cb8e00",
+      "ac67f1c3aff2f50ed4b1975bde67ffe3", "8db6145a60d506cc94f07cef8b27c681",
+  };
+
+  static const char* const kTestDigests10bpp[kNumFilmGrainTestParams] = {
+      "c50be59c62b634ff45ddfbe5b978adfc", "7626286109a2a1eaf0a26f6b2bbab9aa",
+      "f2302988140c47a0724fc55ff523b6ec", "5318e33d8a59a526347ffa6a72ba6ebd",
+      "f2302988140c47a0724fc55ff523b6ec", "f435b5fe98e9d8b6c61fa6f457601c2c",
+      "f435b5fe98e9d8b6c61fa6f457601c2c", "ff07a2944dbe094d01e199098764941c",
+      "11b3e256c74cee2b5679f7457793869a", "89fab5c1db09e242d0494d1c696a774a",
+  };
+
+  static const char* const kTestDigests12bpp[kNumFilmGrainTestParams] = {
+      "1554df49a863a851d146213e09d311a4", "84808c3ed3b5495a62c9d2dd9a08cb26",
+      "bb31f083a3bd9ef26587478b8752f280", "34fdfe61d6871e4882e38062a0725c5c",
+      "bb31f083a3bd9ef26587478b8752f280", "e7b8c3e4508ceabe89b78f10a9e160b8",
+      "e7b8c3e4508ceabe89b78f10a9e160b8", "a0ccc9e3d0f0c9d1f08f1249264d92f5",
+      "7992a96883c8a9a35d6ca8961bc4515b", "de906ce2c0fceed6f168215447b21b16",
+  };
+
+  switch (bitdepth) {
+    case 8:
+      return kTestDigests8bpp[param_index];
+    case 10:
+      return kTestDigests10bpp[param_index];
+    case 12:
+      return kTestDigests12bpp[param_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetBlendLumaTestDigest(int bitdepth) {
+  static const char* const kTestDigests[] = {
+      "de35b16c702690b1d311cdd0973835d7",
+      "60e9f24dcaaa0207a8db5ab5f3c66608",
+      "8e7d44b620bb7768459074be6bfbca7b",
+  };
+
+  assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+  return kTestDigests[(bitdepth - 8) / 2];
+}
+
+const char* GetBlendChromaUTestDigest(int bitdepth,
+                                      int chroma_scaling_from_luma,
+                                      int subsampling_x, int subsampling_y) {
+  static const char* const kTestDigests8bpp[6] = {
+      "36ca194734d45e75079baba1f3ec9e9e", "182b388061f59fd3e24ef4581c536e67",
+      "2e7843b4c624f03316c3cbe1cc835859", "39e6d9606915da6a41168fbb006b55e4",
+      "3f44a4e252d4823544ac66a900dc7983", "1860f0831841f262d66b23f6a6b5833b",
+  };
+
+  static const char* const kTestDigests10bpp[6] = {
+      "2054665564f55750c9588b505eb01ac0", "4d8b0e248f8a6bfc72516aa164e76b0b",
+      "7e549800a4f9fff6833bb7738e272baf", "8de6f30dcda99a37b359fd815e62d2f7",
+      "9b7958a2278a16bce2b7bc31fdd811f5", "c5c3c8cccf6a2b4e40b4a412a5bf4f08",
+  };
+
+  static const char* const kTestDigests12bpp[6] = {
+      "8fad0cc641da35e0d2d8f178c7ce8394", "793eb9d2e6b4ea2e3bb08e7068236155",
+      "9156bd85ab9493d8867a174f920bb1e6", "6834319b4c88e3e0c96b6f8d7efd08dd",
+      "c40e492790d3803a734efbc6feca46e2", "d884c3b1e2c21d98844ca7639e0599a5",
+  };
+
+  const int base_index =
+      3 * chroma_scaling_from_luma + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigests8bpp[base_index];
+    case 10:
+      return kTestDigests10bpp[base_index];
+    case 12:
+      return kTestDigests12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+const char* GetBlendChromaVTestDigest(int bitdepth,
+                                      int chroma_scaling_from_luma,
+                                      int subsampling_x, int subsampling_y) {
+  static const char* const kTestDigests8bpp[6] = {
+      "9a353e4f86d7ebaa980f7f6cfc0995ad", "17589b4039ed49ba16f32db9fae724b7",
+      "76ae8bed48a173b548993b6e1824ff67", "c1458ac9bdfbf0b4d6a175343b17b27b",
+      "fa76d1c8e48957537f26af6a5b54ec14", "313fe3c34568b7f9c5ecb09d419d4ba4",
+  };
+
+  static const char* const kTestDigests10bpp[6] = {
+      "8ab5a8e03f07547260033d6a0b689e3c", "275ede58d311e2f5fd76f222f45a64fc",
+      "ce13916e0f7b02087fd0356534d32770", "165bfc8cda0266936a67fa4ec9b215cb",
+      "ed4382caa936acf1158ff8049d18ffac", "942bdd1344c9182dd7572099fb9372db",
+  };
+
+  static const char* const kTestDigests12bpp[6] = {
+      "70704a1e171a3a70d40b7d0037a75fbc", "62549e2afbf36a1ed405a6574d39c542",
+      "e93889927ab77c6e0767ff071d980c02", "a0c1f6ed78874137710fee7418d80959",
+      "f6283e36a25cb867e30bdf0bfdb2124b", "741c2d48898835b9d9e3bd0b6ac6269a",
+  };
+
+  const int base_index =
+      3 * chroma_scaling_from_luma + subsampling_x + subsampling_y;
+  switch (bitdepth) {
+    case 8:
+      return kTestDigests8bpp[base_index];
+    case 10:
+      return kTestDigests10bpp[base_index];
+    case 12:
+      return kTestDigests12bpp[base_index];
+    default:
+      assert(bitdepth == 8 || bitdepth == 10 || bitdepth == 12);
+      return nullptr;
+  }
+}
+
+// GetFilmGrainRandomNumber() is only invoked with |bits| equal to 11 or 8. Test
+// both values of |bits|.
+TEST(FilmGrainTest, GetFilmGrainRandomNumber) {
+  uint16_t seed = 51968;
+  const struct {
+    int rand;
+    uint16_t seed;
+  } kExpected11[5] = {
+      {812, 25984}, {406, 12992}, {1227, 39264}, {1637, 52400}, {818, 26200},
+  };
+  for (int i = 0; i < 5; ++i) {
+    int rand = GetFilmGrainRandomNumber(11, &seed);
+    EXPECT_EQ(rand, kExpected11[i].rand) << "i = " << i;
+    EXPECT_EQ(seed, kExpected11[i].seed) << "i = " << i;
+  }
+  const struct {
+    int rand;
+    uint16_t seed;
+  } kExpected8[5] = {
+      {179, 45868}, {89, 22934}, {44, 11467}, {150, 38501}, {75, 19250},
+  };
+  for (int i = 0; i < 5; ++i) {
+    int rand = GetFilmGrainRandomNumber(8, &seed);
+    EXPECT_EQ(rand, kExpected8[i].rand) << "i = " << i;
+    EXPECT_EQ(seed, kExpected8[i].seed) << "i = " << i;
+  }
+}
+
+// In FilmGrainParams, if num_u_points and num_v_points are both 0 and
+// chroma_scaling_from_luma is false, GenerateChromaGrains() should set both
+// the u_grain and v_grain arrays to all zeros.
+TEST(FilmGrainTest, GenerateZeroChromaGrains) {
+  FilmGrainParams film_grain_params = {};
+  film_grain_params.apply_grain = true;
+  film_grain_params.update_grain = true;
+  film_grain_params.chroma_scaling = 8;
+  film_grain_params.auto_regression_shift = 6;
+  film_grain_params.grain_seed = 51968;
+
+  int8_t u_grain[73 * 82];
+  int8_t v_grain[73 * 82];
+  const int chroma_width = 44;
+  const int chroma_height = 38;
+
+  // Initialize u_grain and v_grain with arbitrary nonzero values.
+  memset(u_grain, 1, sizeof(u_grain));
+  memset(v_grain, 2, sizeof(v_grain));
+  for (int y = 0; y < chroma_height; ++y) {
+    for (int x = 0; x < chroma_width; ++x) {
+      EXPECT_NE(u_grain[y * chroma_width + x], 0);
+      EXPECT_NE(v_grain[y * chroma_width + x], 0);
+    }
+  }
+
+  FilmGrain<8>::GenerateChromaGrains(film_grain_params, chroma_width,
+                                     chroma_height, u_grain, v_grain);
+
+  for (int y = 0; y < chroma_height; ++y) {
+    for (int x = 0; x < chroma_width; ++x) {
+      EXPECT_EQ(u_grain[y * chroma_width + x], 0);
+      EXPECT_EQ(v_grain[y * chroma_width + x], 0);
+    }
+  }
+}
+
+// First parameter is coefficient lag. Second parameter is the index into
+// |kFilmGrainParams|.
+template <int bitdepth>
+class AutoRegressionTestLuma
+    : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  AutoRegressionTestLuma() {
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    const int index = std::get<0>(GetParam()) - 1;
+    base_luma_auto_regression_func_ =
+        dsp->film_grain.luma_auto_regression[index];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_luma_auto_regression_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    }
+    luma_auto_regression_func_ = dsp->film_grain.luma_auto_regression[index];
+  }
+
+ protected:
+  // |compare| determines whether to compare the output blocks from the SIMD
+  // implementation, if used, and the C implementation.
+  // |saturate| determines whether to set the inputs to maximum values. This is
+  // intended primarily as a way to simplify differences in output when
+  // debugging.
+  void TestAutoRegressiveFilterLuma(int coeff_lag, int param_index,
+                                    int num_runs, bool saturate, bool compare);
+  LumaAutoRegressionFunc luma_auto_regression_func_;
+  LumaAutoRegressionFunc base_luma_auto_regression_func_;
+  GrainType luma_block_buffer_[kLumaBlockSize];
+  GrainType base_luma_block_buffer_[kLumaBlockSize];
+};
+
+// First parameter is coefficient lag. Second parameter is the index into
+// |kFilmGrainParams|.
+template <int bitdepth>
+void AutoRegressionTestLuma<bitdepth>::TestAutoRegressiveFilterLuma(
+    int coeff_lag, int param_index, int num_runs, bool saturate, bool compare) {
+  if (luma_auto_regression_func_ == nullptr) return;
+  // Compare is only needed for NEON tests to compare with C output.
+  if (base_luma_auto_regression_func_ == nullptr && compare) return;
+  FilmGrainParams params = kFilmGrainParams[param_index];
+  params.auto_regression_coeff_lag = coeff_lag;
+  const int grain_max = GetGrainMax<bitdepth>();
+  for (int y = 0; y < kLumaHeight; ++y) {
+    for (int x = 0; x < kLumaWidth; ++x) {
+      if (saturate) {
+        luma_block_buffer_[y * kLumaWidth + x] = grain_max;
+      } else {
+        luma_block_buffer_[y * kLumaWidth + x] =
+            std::min(x - (kLumaWidth >> 1), y - (kLumaHeight >> 1)) *
+            (1 << (bitdepth - 8));
+      }
+    }
+  }
+
+  if (saturate) {
+    memset(params.auto_regression_coeff_y, 127,
+           sizeof(params.auto_regression_coeff_y));
+  }
+  if (compare) {
+    memcpy(base_luma_block_buffer_, luma_block_buffer_,
+           sizeof(luma_block_buffer_));
+  }
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    luma_auto_regression_func_(params, luma_block_buffer_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs > 1) {
+    printf("AutoRegressionLuma lag=%d, param_index=%d: %d us\n", coeff_lag,
+           param_index,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+    return;
+  }
+  if (compare) {
+    base_luma_auto_regression_func_(params, base_luma_block_buffer_);
+    EXPECT_TRUE(test_utils::CompareBlocks(
+        luma_block_buffer_, base_luma_block_buffer_, kLumaWidth, kLumaHeight,
+        kLumaWidth, kLumaWidth, false));
+  } else {
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("AutoRegressionLuma lag=%d, param_index=%d", coeff_lag,
+                        param_index)
+            .c_str(),
+        GetARTestDigestLuma(bitdepth, coeff_lag, param_index),
+        luma_block_buffer_, sizeof(luma_block_buffer_), elapsed_time);
+  }
+}
+
+using AutoRegressionTestLuma8bpp = AutoRegressionTestLuma<8>;
+
+TEST_P(AutoRegressionTestLuma8bpp, AutoRegressiveFilterLuma) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/false,
+                               /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestLuma8bpp, AutoRegressiveFilterLumaSaturated) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/true,
+                               /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestLuma8bpp, DISABLED_Speed) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1e5,
+                               /*saturate=*/false, /*compare=*/false);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using AutoRegressionTestLuma10bpp = AutoRegressionTestLuma<10>;
+
+TEST_P(AutoRegressionTestLuma10bpp, AutoRegressiveFilterLuma) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/false,
+                               /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestLuma10bpp, AutoRegressiveFilterLumaSaturated) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/true,
+                               /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestLuma10bpp, DISABLED_Speed) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1e5,
+                               /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using AutoRegressionTestLuma12bpp = AutoRegressionTestLuma<12>;
+
+TEST_P(AutoRegressionTestLuma12bpp, AutoRegressiveFilterLuma) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/false,
+                               /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestLuma12bpp, AutoRegressiveFilterLumaSaturated) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1, /*saturate=*/true,
+                               /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestLuma12bpp, DISABLED_Speed) {
+  TestAutoRegressiveFilterLuma(std::get<0>(GetParam()), std::get<1>(GetParam()),
+                               1e5,
+                               /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(
+    C, AutoRegressionTestLuma8bpp,
+    testing::Combine(testing::Range(1, 4) /* coeff_lag */,
+                     testing::Range(0, 10) /* param_index */));
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(
+    NEON, AutoRegressionTestLuma8bpp,
+    testing::Combine(testing::Range(1, 4) /* coeff_lag */,
+                     testing::Range(0, 10) /* param_index */));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(
+    C, AutoRegressionTestLuma10bpp,
+    testing::Combine(testing::Range(1, 4) /* coeff_lag */,
+                     testing::Range(0, 10) /* param_index */));
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(
+    NEON, AutoRegressionTestLuma10bpp,
+    testing::Combine(testing::Range(1, 4) /* coeff_lag */,
+                     testing::Range(0, 10) /* param_index */));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(
+    C, AutoRegressionTestLuma12bpp,
+    testing::Combine(testing::Range(1, 4) /* coeff_lag */,
+                     testing::Range(0, 10) /* param_index */));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct AutoRegressionChromaTestParam {
+  explicit AutoRegressionChromaTestParam(const std::tuple<int, int>& in)
+      : coeff_lag(std::get<0>(in)) {
+    switch (std::get<1>(in)) {
+      case 0:
+        subsampling_x = 0;
+        subsampling_y = 0;
+        break;
+      case 1:
+        subsampling_x = 1;
+        subsampling_y = 0;
+        break;
+      default:
+        assert(std::get<1>(in) == 2);
+        subsampling_x = 1;
+        subsampling_y = 1;
+    }
+  }
+  const int coeff_lag;
+  int subsampling_x;
+  int subsampling_y;
+};
+
+template <int bitdepth>
+class AutoRegressionTestChroma
+    : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  AutoRegressionTestChroma() {
+    AutoRegressionChromaTestParam test_param(GetParam());
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    // This test suite does not cover num_y_points == 0. This should be covered
+    // in the test of the full synthesis process.
+    base_chroma_auto_regression_func_ =
+        dsp->film_grain.chroma_auto_regression[1][test_param.coeff_lag];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_chroma_auto_regression_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    }
+    chroma_auto_regression_func_ =
+        dsp->film_grain.chroma_auto_regression[1][test_param.coeff_lag];
+  }
+
+  ~AutoRegressionTestChroma() override = default;
+
+ protected:
+  // |compare| determines whether to compare the output blocks from the SIMD
+  // implementation, if used, and the C implementation.
+  // |saturate| determines whether to set the inputs to maximum values. This is
+  // intended primarily as a way to simplify differences in output when
+  // debugging.
+  void TestAutoRegressiveFilterChroma(int coeff_lag, int subsampling_x,
+                                      int subsampling_y, int num_runs,
+                                      bool saturate, bool compare);
+  ChromaAutoRegressionFunc chroma_auto_regression_func_;
+  ChromaAutoRegressionFunc base_chroma_auto_regression_func_;
+  GrainType luma_block_buffer_[kLumaBlockSize];
+  GrainType u_block_buffer_[kChromaBlockSize];
+  GrainType v_block_buffer_[kChromaBlockSize];
+  GrainType base_u_block_buffer_[kChromaBlockSize];
+  GrainType base_v_block_buffer_[kChromaBlockSize];
+};
+
+template <int bitdepth>
+void AutoRegressionTestChroma<bitdepth>::TestAutoRegressiveFilterChroma(
+    int coeff_lag, int subsampling_x, int subsampling_y, int num_runs,
+    bool saturate, bool compare) {
+  if (chroma_auto_regression_func_ == nullptr) return;
+  // Compare is only needed for NEON tests to compare with C output.
+  if (base_chroma_auto_regression_func_ == nullptr && compare) return;
+
+  // This function relies on the first set of sampled params for basics. The
+  // test param generators are used for coverage.
+  FilmGrainParams params = kFilmGrainParams[0];
+  params.auto_regression_coeff_lag = coeff_lag;
+  const int grain_max = GetGrainMax<bitdepth>();
+  const int grain_min = GetGrainMin<bitdepth>();
+  const int chroma_width =
+      (subsampling_x != 0) ? kMinChromaWidth : kMaxChromaWidth;
+  const int chroma_height =
+      (subsampling_y != 0) ? kMinChromaHeight : kMaxChromaHeight;
+  if (saturate) {
+    memset(params.auto_regression_coeff_u, 127,
+           sizeof(params.auto_regression_coeff_u));
+    memset(params.auto_regression_coeff_v, 127,
+           sizeof(params.auto_regression_coeff_v));
+    for (int y = 0; y < kLumaHeight; ++y) {
+      for (int x = 0; x < kLumaWidth; ++x) {
+        // This loop relies on the fact that kMaxChromaWidth == kLumaWidth.
+        luma_block_buffer_[y * kLumaWidth + x] = grain_max;
+        u_block_buffer_[y * kLumaWidth + x] = grain_max;
+        v_block_buffer_[y * kLumaWidth + x] = grain_max;
+      }
+    }
+  } else {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    // Allow any valid grain values.
+    const int random_range = grain_max - grain_min + 1;
+    for (int y = 0; y < kLumaHeight; ++y) {
+      for (int x = 0; x < kLumaWidth; ++x) {
+        // This loop relies on the fact that kMaxChromaWidth == kLumaWidth.
+        const int random_y = rnd(random_range);
+        luma_block_buffer_[y * kLumaWidth + x] = random_y + grain_min;
+        const int random_u = rnd(random_range);
+        u_block_buffer_[y * kLumaWidth + x] = random_u + grain_min;
+        const int random_v = rnd(random_range);
+        v_block_buffer_[y * kLumaWidth + x] = random_v + grain_min;
+      }
+    }
+  }
+  if (compare) {
+    memcpy(base_u_block_buffer_, u_block_buffer_, sizeof(u_block_buffer_));
+    memcpy(base_v_block_buffer_, v_block_buffer_, sizeof(v_block_buffer_));
+  }
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    chroma_auto_regression_func_(params, luma_block_buffer_, subsampling_x,
+                                 subsampling_y, u_block_buffer_,
+                                 v_block_buffer_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs > 1) {
+    printf("AutoRegressionChroma lag=%d, sub_x=%d, sub_y=%d: %d us\n",
+           coeff_lag, subsampling_x, subsampling_y,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+    return;
+  }
+  if (compare) {
+    base_chroma_auto_regression_func_(params, luma_block_buffer_, subsampling_x,
+                                      subsampling_y, base_u_block_buffer_,
+                                      base_v_block_buffer_);
+    EXPECT_TRUE(test_utils::CompareBlocks(u_block_buffer_, base_u_block_buffer_,
+                                          chroma_width, chroma_height,
+                                          chroma_width, chroma_width, false));
+    EXPECT_TRUE(test_utils::CompareBlocks(v_block_buffer_, base_v_block_buffer_,
+                                          chroma_width, chroma_height,
+                                          chroma_width, chroma_width, false));
+  } else {
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("AutoRegressionChromaU lag=%d, sub_x=%d, sub_y=%d",
+                        coeff_lag, subsampling_x, subsampling_y)
+            .c_str(),
+        GetARTestDigestChromaU(bitdepth, coeff_lag, subsampling_x,
+                               subsampling_y),
+        u_block_buffer_, sizeof(u_block_buffer_), elapsed_time);
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("AutoRegressionChromaV lag=%d, sub_x=%d, sub_y=%d",
+                        coeff_lag, subsampling_x, subsampling_y)
+            .c_str(),
+        GetARTestDigestChromaV(bitdepth, coeff_lag, subsampling_x,
+                               subsampling_y),
+        v_block_buffer_, sizeof(v_block_buffer_), elapsed_time);
+  }
+}
+
+using AutoRegressionTestChroma8bpp = AutoRegressionTestChroma<8>;
+
+TEST_P(AutoRegressionTestChroma8bpp, AutoRegressiveFilterChroma) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1,
+                                 /*saturate=*/false,
+                                 /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestChroma8bpp, AutoRegressiveFilterChromaSaturated) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1, /*saturate=*/true,
+                                 /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestChroma8bpp, DISABLED_Speed) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(
+      test_param.coeff_lag, test_param.subsampling_x, test_param.subsampling_y,
+      // Subsampling cuts each dimension of the chroma blocks in half, so run
+      // twice as many times to compensate.
+      1e5 * (1 << (test_param.subsampling_y + test_param.subsampling_x)),
+      /*saturate=*/false, /*compare=*/false);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using AutoRegressionTestChroma10bpp = AutoRegressionTestChroma<10>;
+
+TEST_P(AutoRegressionTestChroma10bpp, AutoRegressiveFilterChroma) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1,
+                                 /*saturate=*/false,
+                                 /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestChroma10bpp, AutoRegressiveFilterChromaSaturated) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1, /*saturate=*/true,
+                                 /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestChroma10bpp, DISABLED_Speed) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(
+      test_param.coeff_lag, test_param.subsampling_x, test_param.subsampling_y,
+      // Subsampling cuts each dimension of the chroma blocks in half, so run
+      // twice as many times to compensate.
+      1e5 * (1 << (test_param.subsampling_y + test_param.subsampling_x)),
+      /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using AutoRegressionTestChroma12bpp = AutoRegressionTestChroma<12>;
+
+TEST_P(AutoRegressionTestChroma12bpp, AutoRegressiveFilterChroma) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1,
+                                 /*saturate=*/false,
+                                 /*compare=*/false);
+}
+
+TEST_P(AutoRegressionTestChroma12bpp, AutoRegressiveFilterChromaSaturated) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(test_param.coeff_lag, test_param.subsampling_x,
+                                 test_param.subsampling_y, 1, /*saturate=*/true,
+                                 /*compare=*/true);
+}
+
+TEST_P(AutoRegressionTestChroma12bpp, DISABLED_Speed) {
+  AutoRegressionChromaTestParam test_param(GetParam());
+  TestAutoRegressiveFilterChroma(
+      test_param.coeff_lag, test_param.subsampling_x, test_param.subsampling_y,
+      // Subsampling cuts each dimension of the chroma blocks in half, so run
+      // twice as many times to compensate.
+      1e5 * (1 << (test_param.subsampling_y + test_param.subsampling_x)),
+      /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, AutoRegressionTestChroma8bpp,
+                         testing::Combine(testing::Range(0, 4) /* coeff_lag */,
+                                          testing::Range(0,
+                                                         3) /* subsampling */));
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, AutoRegressionTestChroma10bpp,
+                         testing::Combine(testing::Range(0, 4) /* coeff_lag */,
+                                          testing::Range(0,
+                                                         3) /* subsampling */));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, AutoRegressionTestChroma12bpp,
+                         testing::Combine(testing::Range(0, 4) /* coeff_lag */,
+                                          testing::Range(0,
+                                                         3) /* subsampling */));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, AutoRegressionTestChroma8bpp,
+                         testing::Combine(testing::Range(0, 4) /* coeff_lag */,
+                                          testing::Range(0,
+                                                         3) /* subsampling */));
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(NEON, AutoRegressionTestChroma10bpp,
+                         testing::Combine(testing::Range(0, 4) /* coeff_lag */,
+                                          testing::Range(0,
+                                                         3) /* subsampling */));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+#endif  // LIBGAV1_ENABLE_NEON
+
+template <int bitdepth>
+class GrainGenerationTest : public testing::TestWithParam<int> {
+ protected:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  void TestGenerateGrainLuma(int param_index, int num_runs);
+
+  GrainType luma_block_buffer_[kLumaBlockSize];
+};
+
+template <int bitdepth>
+void GrainGenerationTest<bitdepth>::TestGenerateGrainLuma(int param_index,
+                                                          int num_runs) {
+  FilmGrainParams params = kFilmGrainParams[param_index];
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    FilmGrain<bitdepth>::GenerateLumaGrain(params, luma_block_buffer_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs == 1) {
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("GenerateGrainLuma param_index=%d", param_index)
+            .c_str(),
+        GetGrainGenerationTestDigestLuma(bitdepth, param_index),
+        luma_block_buffer_, sizeof(luma_block_buffer_), elapsed_time);
+  } else {
+    printf("GenerateGrainLuma param_index=%d: %d us\n", param_index,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+}
+
+using GrainGenerationTest8bpp = GrainGenerationTest<8>;
+
+TEST_P(GrainGenerationTest8bpp, GenerateGrainLuma) {
+  TestGenerateGrainLuma(GetParam(), 1);
+}
+
+TEST_P(GrainGenerationTest8bpp, DISABLED_LumaSpeed) {
+  TestGenerateGrainLuma(GetParam(), 1e5);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using GrainGenerationTest10bpp = GrainGenerationTest<10>;
+
+TEST_P(GrainGenerationTest10bpp, GenerateGrainLuma) {
+  TestGenerateGrainLuma(GetParam(), 1);
+}
+
+TEST_P(GrainGenerationTest10bpp, DISABLED_LumaSpeed) {
+  TestGenerateGrainLuma(GetParam(), 1e5);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using GrainGenerationTest12bpp = GrainGenerationTest<12>;
+
+TEST_P(GrainGenerationTest12bpp, GenerateGrainLuma) {
+  TestGenerateGrainLuma(GetParam(), 1);
+}
+
+TEST_P(GrainGenerationTest12bpp, DISABLED_LumaSpeed) {
+  TestGenerateGrainLuma(GetParam(), 1e5);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, GrainGenerationTest8bpp,
+                         testing::Range(0, 10) /* param_index */);
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, GrainGenerationTest10bpp,
+                         testing::Range(0, 10) /* param_index */);
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, GrainGenerationTest12bpp,
+                         testing::Range(0, 10) /* param_index */);
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+// This param type is used for both ConstructStripesTest and
+// ConstructImageTest.
+struct ConstructNoiseTestParam {
+  explicit ConstructNoiseTestParam(const std::tuple<int, int>& in)
+      : overlap_flag(std::get<0>(in)) {
+    switch (std::get<1>(in)) {
+      case 0:
+        subsampling_x = 0;
+        subsampling_y = 0;
+        break;
+      case 1:
+        subsampling_x = 1;
+        subsampling_y = 0;
+        break;
+      default:
+        assert(std::get<1>(in) == 2);
+        subsampling_x = 1;
+        subsampling_y = 1;
+    }
+  }
+  const int overlap_flag;
+  int subsampling_x;
+  int subsampling_y;
+};
+
+template <int bitdepth>
+class ConstructStripesTest
+    : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  ConstructStripesTest() {
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    base_construct_noise_stripes_func_ =
+        dsp->film_grain.construct_noise_stripes[std::get<0>(GetParam())];
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_construct_noise_stripes_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    }
+    construct_noise_stripes_func_ =
+        dsp->film_grain.construct_noise_stripes[std::get<0>(GetParam())];
+  }
+
+  ~ConstructStripesTest() override = default;
+
+ protected:
+  // |compare| determines whether to compare the output blocks from the SIMD
+  // implementation, if used, and the C implementation.
+  // |saturate| determines whether to set the inputs to maximum values. This is
+  // intended primarily as a way to simplify differences in output when
+  // debugging.
+  void TestConstructNoiseStripes(int overlap_flag, int subsampling_x,
+                                 int subsampling_y, int num_runs, bool saturate,
+                                 bool compare);
+  ConstructNoiseStripesFunc construct_noise_stripes_func_;
+  ConstructNoiseStripesFunc base_construct_noise_stripes_func_;
+  GrainType grain_buffer_[kLumaBlockSize];
+  Array2DView<GrainType> noise_stripes_;
+  // Owns the memory that noise_stripes_ points to.
+  std::unique_ptr<GrainType[]> stripe_buffer_;
+  Array2DView<GrainType> base_noise_stripes_;
+  // Owns the memory that base_stripe_buffer_ points to.
+  std::unique_ptr<GrainType[]> base_stripe_buffer_;
+};
+
+template <int bitdepth>
+void ConstructStripesTest<bitdepth>::TestConstructNoiseStripes(
+    int overlap_flag, int subsampling_x, int subsampling_y, int num_runs,
+    bool saturate, bool compare) {
+  if (construct_noise_stripes_func_ == nullptr) return;
+  // Compare is only needed for NEON tests to compare with C output.
+  if (base_construct_noise_stripes_func_ == nullptr && compare) return;
+
+  const int stripe_width = ((kFrameWidth + subsampling_x) >> subsampling_x);
+  const int stripe_height = kNoiseStripeHeight;
+  const int stripe_size = stripe_height * stripe_width;
+  const int stripe_buffer_size = stripe_size * kNumTestStripes;
+  if (compare) {
+    base_stripe_buffer_.reset(new (
+        std::nothrow) GrainType[stripe_buffer_size + kNoiseStripePadding]());
+    ASSERT_NE(base_stripe_buffer_, nullptr);
+    base_noise_stripes_.Reset(kNumTestStripes, stripe_size,
+                              base_stripe_buffer_.get());
+  }
+  stripe_buffer_.reset(
+      new (std::nothrow) GrainType[stripe_buffer_size + kNoiseStripePadding]());
+  ASSERT_NE(stripe_buffer_, nullptr);
+  noise_stripes_.Reset(kNumTestStripes, stripe_size, stripe_buffer_.get());
+
+  const int grain_max = GetGrainMax<bitdepth>();
+  const int grain_min = GetGrainMin<bitdepth>();
+  if (saturate) {
+    for (int y = 0; y < kLumaHeight; ++y) {
+      for (int x = 0; x < kLumaWidth; ++x) {
+        grain_buffer_[y * kLumaWidth + x] = grain_max;
+      }
+    }
+  } else {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    // Allow any valid grain values.
+    const int random_range = grain_max - grain_min + 1;
+    for (int y = 0; y < kLumaHeight; ++y) {
+      for (int x = 0; x < kLumaWidth; ++x) {
+        grain_buffer_[y * kLumaWidth + x] = grain_min + rnd(random_range);
+      }
+    }
+  }
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    construct_noise_stripes_func_(grain_buffer_, 68, kFrameWidth, kFrameHeight,
+                                  subsampling_x, subsampling_y,
+                                  &noise_stripes_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs > 1) {
+    printf(
+        "ConstructNoiseStripes Speed Test for overlap=%d, sub_x=%d, "
+        "sub_y=%d: %d us\n",
+        overlap_flag, subsampling_x, subsampling_y,
+        static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+    return;
+  }
+  if (compare) {
+    base_construct_noise_stripes_func_(grain_buffer_, 68, kFrameWidth,
+                                       kFrameHeight, subsampling_x,
+                                       subsampling_y, &base_noise_stripes_);
+
+    constexpr int kCompareWidth = 64;
+    for (int stripe = 0; stripe < kNumTestStripes;) {
+      EXPECT_TRUE(test_utils::CompareBlocks(
+          noise_stripes_[stripe], base_noise_stripes_[stripe], kCompareWidth,
+          stripe_height, stripe_width, stripe_width, /*check_padding=*/false,
+          /*print_diff=*/false));
+    }
+  } else {
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("ConstructNoiseStripes overlap=%d, sub_x=%d, sub_y=%d",
+                        overlap_flag, subsampling_x, subsampling_y)
+            .c_str(),
+        GetConstructStripesTestDigest(bitdepth, overlap_flag, subsampling_x,
+                                      subsampling_y),
+        noise_stripes_[0], stripe_buffer_size, elapsed_time);
+  }
+}
+
+using ConstructStripesTest8bpp = ConstructStripesTest<8>;
+
+TEST_P(ConstructStripesTest8bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/false, /*compare=*/false);
+}
+
+TEST_P(ConstructStripesTest8bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/true, /*compare=*/true);
+}
+TEST_P(ConstructStripesTest8bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/500,
+                            /*saturate=*/false, /*compare=*/false);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using ConstructStripesTest10bpp = ConstructStripesTest<10>;
+
+TEST_P(ConstructStripesTest10bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/false, /*compare=*/false);
+}
+TEST_P(ConstructStripesTest10bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/true, /*compare=*/true);
+}
+
+TEST_P(ConstructStripesTest10bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/500,
+                            /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using ConstructStripesTest12bpp = ConstructStripesTest<12>;
+
+TEST_P(ConstructStripesTest12bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/false, /*compare=*/false);
+}
+TEST_P(ConstructStripesTest12bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/1,
+                            /*saturate=*/true, /*compare=*/true);
+}
+
+TEST_P(ConstructStripesTest12bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseStripes(test_params.overlap_flag, test_params.subsampling_x,
+                            test_params.subsampling_y, /*num_runs=*/500,
+                            /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, ConstructStripesTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, ConstructStripesTest10bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, ConstructStripesTest12bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+template <int bitdepth>
+class ConstructImageTest : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  ConstructImageTest() {
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+    base_construct_noise_image_overlap_func_ =
+        dsp->film_grain.construct_noise_image_overlap;
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "C/")) {
+      base_construct_noise_image_overlap_func_ = nullptr;
+    } else if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    }
+    construct_noise_image_overlap_func_ =
+        dsp->film_grain.construct_noise_image_overlap;
+  }
+
+  ~ConstructImageTest() override = default;
+
+ protected:
+  // |compare| determines whether to compare the output blocks from the SIMD
+  // implementation, if used, and the C implementation.
+  // |saturate| determines whether to set the inputs to maximum values. This is
+  // intended primarily as a way to simplify differences in output when
+  // debugging.
+  void TestConstructNoiseImage(int overlap_flag, int subsampling_x,
+                               int subsampling_y, int num_runs, bool saturate,
+                               bool compare);
+  ConstructNoiseImageOverlapFunc construct_noise_image_overlap_func_;
+  ConstructNoiseImageOverlapFunc base_construct_noise_image_overlap_func_;
+  Array2DView<GrainType> noise_stripes_;
+  // Owns the memory that noise_stripes_ points to.
+  std::unique_ptr<GrainType[]> stripe_buffer_;
+  Array2D<GrainType> noise_image_;
+  Array2D<GrainType> base_noise_image_;
+};
+
+template <int bitdepth>
+void ConstructImageTest<bitdepth>::TestConstructNoiseImage(
+    int overlap_flag, int subsampling_x, int subsampling_y, int num_runs,
+    bool saturate, bool compare) {
+  if (construct_noise_image_overlap_func_ == nullptr) return;
+  // Compare is only needed for NEON tests to compare with C output.
+  if (base_construct_noise_image_overlap_func_ == nullptr && compare) return;
+
+  const int image_width = ((kFrameWidth + subsampling_x) >> subsampling_x);
+  const int image_height = ((kFrameHeight + subsampling_y) >> subsampling_y);
+  const int stripe_height =
+      ((kNoiseStripeHeight + subsampling_y) >> subsampling_y);
+  const int image_stride = image_width + kNoiseImagePadding;
+  const int stripe_size = stripe_height * image_width;
+  if (compare) {
+    ASSERT_TRUE(base_noise_image_.Reset(image_height, image_stride,
+                                        /*zero_initialize=*/false));
+  }
+  ASSERT_TRUE(noise_image_.Reset(image_height, image_stride,
+                                 /*zero_initialize=*/false));
+  // Stride between stripe rows is |image_width|. Padding is only at the
+  // end of the final row of the final stripe to protect from overreads.
+  stripe_buffer_.reset(
+      new (std::nothrow)
+          GrainType[kNumTestStripes * stripe_size + kNoiseStripePadding]);
+  ASSERT_NE(stripe_buffer_, nullptr);
+  noise_stripes_.Reset(kNumTestStripes, stripe_size, stripe_buffer_.get());
+
+  const int grain_max = GetGrainMax<bitdepth>();
+  const int grain_min = GetGrainMin<bitdepth>();
+  if (saturate) {
+    for (int i = 0; i < stripe_size; ++i) {
+      noise_stripes_[0][i] = grain_max;
+    }
+    for (int stripe = 1; stripe < kNumTestStripes; ++stripe) {
+      memcpy(noise_stripes_[stripe], noise_stripes_[0],
+             stripe_size * sizeof(noise_stripes_[0][0]));
+    }
+  } else {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    // Allow any valid grain values.
+    const int random_range = grain_max - grain_min + 1;
+    for (int stripe = 0; stripe < kNumTestStripes; ++stripe) {
+      // Assign all allocated memory for this stripe.
+      for (int i = 0; i < stripe_height; ++i) {
+        for (int x = 0; x < image_width; ++x) {
+          noise_stripes_[stripe][i * image_width + x] =
+              grain_min + rnd(random_range);
+        }
+      }
+    }
+  }
+
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    FilmGrain<bitdepth>::ConstructNoiseImage(
+        &noise_stripes_, kFrameWidth, kFrameHeight, subsampling_x,
+        subsampling_y, overlap_flag << (1 - subsampling_y), &noise_image_);
+    if (overlap_flag == 1) {
+      construct_noise_image_overlap_func_(&noise_stripes_, kFrameWidth,
+                                          kFrameHeight, subsampling_x,
+                                          subsampling_y, &noise_image_);
+    }
+  }
+
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs > 1) {
+    printf(
+        "ConstructNoiseImage Speed Test for overlap=%d, sub_x=%d, "
+        "sub_y=%d: %d us\n",
+        overlap_flag, subsampling_x, subsampling_y,
+        static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+    return;
+  }
+  if (compare) {
+    FilmGrain<bitdepth>::ConstructNoiseImage(
+        &noise_stripes_, kFrameWidth, kFrameHeight, subsampling_x,
+        subsampling_y, overlap_flag << (1 - subsampling_y), &base_noise_image_);
+    if (overlap_flag == 1) {
+      base_construct_noise_image_overlap_func_(
+          &noise_stripes_, kFrameWidth, kFrameHeight, subsampling_x,
+          subsampling_y, &base_noise_image_);
+    }
+    constexpr int kCompareWidth = 72;
+    constexpr int kCompareHeight = 72;
+    EXPECT_TRUE(test_utils::CompareBlocks(
+        noise_image_[0], base_noise_image_[0], kCompareWidth, kCompareHeight,
+        image_stride, image_stride, /*check_padding=*/false,
+        /*print_diff=*/false));
+  } else {
+    printf("BD%d \"%s\",\n", bitdepth,
+           test_utils::GetMd5Sum(noise_image_[0], image_width, image_height,
+                                 image_stride)
+               .c_str());
+    test_utils::CheckMd5Digest(
+        "FilmGrain",
+        absl::StrFormat("ConstructNoiseImage overlap=%d, sub_x=%d, sub_y=%d",
+                        overlap_flag, subsampling_x, subsampling_y)
+            .c_str(),
+        GetConstructImageTestDigest(bitdepth, overlap_flag, subsampling_x,
+                                    subsampling_y),
+        noise_image_[0], image_width, image_height, image_stride, elapsed_time);
+  }
+}
+
+using ConstructImageTest8bpp = ConstructImageTest<8>;
+
+TEST_P(ConstructImageTest8bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/false, /*compare=*/false);
+}
+
+TEST_P(ConstructImageTest8bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/true, /*compare=*/true);
+}
+
+TEST_P(ConstructImageTest8bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/500,
+                          /*saturate=*/false, /*compare=*/false);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using ConstructImageTest10bpp = ConstructImageTest<10>;
+
+TEST_P(ConstructImageTest10bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/false, /*compare=*/false);
+}
+
+TEST_P(ConstructImageTest10bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/true, /*compare=*/true);
+}
+
+TEST_P(ConstructImageTest10bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/500,
+                          /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using ConstructImageTest12bpp = ConstructImageTest<12>;
+
+TEST_P(ConstructImageTest12bpp, RandomValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/false, /*compare=*/false);
+}
+
+TEST_P(ConstructImageTest12bpp, SaturatedValues) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/1,
+                          /*saturate=*/true, /*compare=*/true);
+}
+
+TEST_P(ConstructImageTest12bpp, DISABLED_Speed) {
+  ConstructNoiseTestParam test_params(GetParam());
+  TestConstructNoiseImage(test_params.overlap_flag, test_params.subsampling_x,
+                          test_params.subsampling_y, /*num_runs=*/500,
+                          /*saturate=*/false, /*compare=*/false);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, ConstructImageTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ConstructImageTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_ENABLE_NEON
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, ConstructImageTest10bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, ConstructImageTest12bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+template <int bitdepth>
+class ScalingLookupTableTest : public testing::TestWithParam<int> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  ScalingLookupTableTest() {
+    test_utils::ResetDspTable(bitdepth);
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    }
+    initialize_func_ = dsp->film_grain.initialize_scaling_lut;
+  }
+  ~ScalingLookupTableTest() override = default;
+
+ protected:
+  void TestSpeed(int num_runs);
+  void ZeroPoints();
+
+ private:
+  static constexpr int kScalingLutBufferLength =
+      (kScalingLookupTableSize + kScalingLookupTablePadding) << (bitdepth - 8);
+  dsp::InitializeScalingLutFunc initialize_func_;
+  int16_t scaling_lut_[kScalingLutBufferLength];
+};
+
+template <int bitdepth>
+void ScalingLookupTableTest<bitdepth>::TestSpeed(int num_runs) {
+  if (initialize_func_ == nullptr) return;
+  const int param_index = GetParam();
+  const FilmGrainParams& params = kFilmGrainParams[param_index];
+  const absl::Time start = absl::Now();
+  Memset(scaling_lut_, 0, kScalingLutBufferLength);
+  for (int i = 0; i < num_runs; ++i) {
+    initialize_func_(params.num_y_points, params.point_y_value,
+                     params.point_y_scaling, scaling_lut_,
+                     kScalingLutBufferLength);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  if (num_runs > 1) {
+    printf("InitializeScalingLut: %d us\n",
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+    return;
+  }
+  test_utils::CheckMd5Digest(
+      "FilmGrain",
+      absl::StrFormat("InitializeScalingLut for param set: %d", param_index)
+          .c_str(),
+      GetScalingInitTestDigest(param_index, bitdepth), scaling_lut_,
+      (sizeof(scaling_lut_[0]) * kScalingLookupTableSize) << (bitdepth - 8),
+      elapsed_time);
+}
+
+template <int bitdepth>
+void ScalingLookupTableTest<bitdepth>::ZeroPoints() {
+  if (initialize_func_ == nullptr) return;
+  const int param_index = GetParam();
+  const FilmGrainParams& params = kFilmGrainParams[param_index];
+  initialize_func_(0, params.point_y_value, params.point_y_scaling,
+                   scaling_lut_, kScalingLookupTableSize);
+  for (int i = 0; i < kScalingLookupTableSize; ++i) {
+    ASSERT_EQ(scaling_lut_[i], 0);
+  }
+}
+
+using ScalingLookupTableTest8bpp = ScalingLookupTableTest<8>;
+
+TEST_P(ScalingLookupTableTest8bpp, ZeroPoints) { ZeroPoints(); }
+
+TEST_P(ScalingLookupTableTest8bpp, Correctness) { TestSpeed(/*num_runs=*/1); }
+
+TEST_P(ScalingLookupTableTest8bpp, DISABLED_Speed) {
+  TestSpeed(/*num_runs=*/1e5);
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using ScalingLookupTableTest10bpp = ScalingLookupTableTest<10>;
+
+TEST_P(ScalingLookupTableTest10bpp, ZeroPoints) { ZeroPoints(); }
+
+TEST_P(ScalingLookupTableTest10bpp, Correctness) { TestSpeed(/*num_runs=*/1); }
+
+TEST_P(ScalingLookupTableTest10bpp, DISABLED_Speed) {
+  TestSpeed(/*num_runs=*/1e5);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using ScalingLookupTableTest12bpp = ScalingLookupTableTest<12>;
+
+TEST_P(ScalingLookupTableTest12bpp, ZeroPoints) { ZeroPoints(); }
+
+TEST_P(ScalingLookupTableTest12bpp, Correctness) { TestSpeed(/*num_runs=*/1); }
+
+TEST_P(ScalingLookupTableTest12bpp, DISABLED_Speed) {
+  TestSpeed(/*num_runs=*/1e5);
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+INSTANTIATE_TEST_SUITE_P(C, ScalingLookupTableTest8bpp,
+                         testing::Range(0, kNumFilmGrainTestParams));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ScalingLookupTableTest8bpp,
+                         testing::Range(0, kNumFilmGrainTestParams));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+INSTANTIATE_TEST_SUITE_P(C, ScalingLookupTableTest10bpp,
+                         testing::Range(0, kNumFilmGrainTestParams));
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ScalingLookupTableTest10bpp,
+                         testing::Range(0, kNumFilmGrainTestParams));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+INSTANTIATE_TEST_SUITE_P(C, ScalingLookupTableTest12bpp,
+                         testing::Range(0, kNumFilmGrainTestParams));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+struct BlendNoiseTestParam {
+  explicit BlendNoiseTestParam(const std::tuple<int, int>& in)
+      : chroma_scaling_from_luma(std::get<0>(in)) {
+    switch (std::get<1>(in)) {
+      case 0:
+        subsampling_x = 0;
+        subsampling_y = 0;
+        break;
+      case 1:
+        subsampling_x = 1;
+        subsampling_y = 0;
+        break;
+      default:
+        assert(std::get<1>(in) == 2);
+        subsampling_x = 1;
+        subsampling_y = 1;
+    }
+  }
+  const int chroma_scaling_from_luma;
+  int subsampling_x;
+  int subsampling_y;
+};
+
+template <int bitdepth, typename Pixel>
+class BlendNoiseTest : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  using GrainType =
+      typename std::conditional<bitdepth == 8, int8_t, int16_t>::type;
+
+  BlendNoiseTest() {
+    test_utils::ResetDspTable(bitdepth);
+    FilmGrainInit_C();
+    const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      FilmGrainInit_SSE4_1();
+    }
+    const BlendNoiseTestParam test_param(GetParam());
+    chroma_scaling_from_luma_ = test_param.chroma_scaling_from_luma;
+    blend_luma_func_ = dsp->film_grain.blend_noise_luma;
+    blend_chroma_func_ =
+        dsp->film_grain.blend_noise_chroma[chroma_scaling_from_luma_];
+    subsampling_x_ = test_param.subsampling_x;
+    subsampling_y_ = test_param.subsampling_y;
+
+    uv_width_ = (width_ + subsampling_x_) >> subsampling_x_;
+    uv_height_ = (height_ + subsampling_y_) >> subsampling_y_;
+    uv_stride_ = uv_width_ * sizeof(Pixel);
+    y_stride_ = width_ * sizeof(Pixel);
+    const size_t buffer_size =
+        sizeof(Pixel) * (width_ * height_ + 2 * uv_width_ * uv_height_ +
+                         3 * kBorderPixelsFilmGrain);
+    source_buffer_.reset(new (std::nothrow) uint8_t[buffer_size]);
+    memset(source_buffer_.get(), 0, sizeof(source_buffer_[0]) * buffer_size);
+    dest_buffer_.reset(new (std::nothrow) uint8_t[buffer_size]);
+    memset(dest_buffer_.get(), 0, sizeof(dest_buffer_[0]) * buffer_size);
+    source_plane_y_ = source_buffer_.get();
+    source_plane_u_ =
+        source_plane_y_ + y_stride_ * height_ + kBorderPixelsFilmGrain;
+    source_plane_v_ =
+        source_plane_u_ + uv_stride_ * uv_height_ + kBorderPixelsFilmGrain;
+    dest_plane_y_ = dest_buffer_.get();
+    dest_plane_u_ =
+        dest_plane_y_ + y_stride_ * height_ + kBorderPixelsFilmGrain;
+    dest_plane_v_ =
+        dest_plane_u_ + uv_stride_ * uv_height_ + kBorderPixelsFilmGrain;
+  }
+  ~BlendNoiseTest() override = default;
+
+ protected:
+  void TestSpeed(int num_runs);
+
+ private:
+  static constexpr int kScalingLutBufferLength =
+      (kScalingLookupTableSize + kScalingLookupTablePadding) << 2;
+
+  void ConvertScalingLut10bpp(int16_t* scaling_lut_10bpp,
+                              const int16_t* src_scaling_lut);
+  dsp::BlendNoiseWithImageLumaFunc blend_luma_func_;
+  dsp::BlendNoiseWithImageChromaFunc blend_chroma_func_;
+
+  const int width_ = 1921;
+  const int height_ = 1081;
+  int chroma_scaling_from_luma_ = 0;
+  int subsampling_x_ = 0;
+  int subsampling_y_ = 0;
+  int uv_width_ = 0;
+  int uv_height_ = 0;
+  int uv_stride_ = 0;
+  int y_stride_ = 0;
+  // This holds the data that |source_plane_y_|, |source_plane_u_|, and
+  // |source_plane_v_| point to.
+  std::unique_ptr<uint8_t[]> source_buffer_;
+  // This holds the data that |dest_plane_y_|, |dest_plane_u_|, and
+  // |dest_plane_v_| point to.
+  std::unique_ptr<uint8_t[]> dest_buffer_;
+  uint8_t* source_plane_y_ = nullptr;
+  uint8_t* source_plane_u_ = nullptr;
+  uint8_t* source_plane_v_ = nullptr;
+  uint8_t* dest_plane_y_ = nullptr;
+  uint8_t* dest_plane_u_ = nullptr;
+  uint8_t* dest_plane_v_ = nullptr;
+  Array2D<GrainType> noise_image_[kMaxPlanes];
+  int16_t scaling_lut_10bpp_y_[kScalingLutBufferLength];
+  int16_t scaling_lut_10bpp_u_[kScalingLutBufferLength];
+  int16_t scaling_lut_10bpp_v_[kScalingLutBufferLength];
+};
+
+template <int bitdepth, typename Pixel>
+void BlendNoiseTest<bitdepth, Pixel>::ConvertScalingLut10bpp(
+    int16_t* scaling_lut_10bpp, const int16_t* src_scaling_lut) {
+  for (int i = 0; i < kScalingLookupTableSize - 1; ++i) {
+    const int x_base = i << 2;
+    const int start = src_scaling_lut[i];
+    const int end_index = std::min(i + 1, kScalingLookupTableSize - 1);
+    const int end = src_scaling_lut[end_index];
+    const int delta = end - start;
+    scaling_lut_10bpp[x_base] = start;
+    scaling_lut_10bpp[x_base + 1] = start + RightShiftWithRounding(delta, 2);
+    scaling_lut_10bpp[x_base + 2] =
+        start + RightShiftWithRounding(2 * delta, 2);
+    scaling_lut_10bpp[x_base + 3] =
+        start + RightShiftWithRounding(3 * delta, 2);
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void BlendNoiseTest<bitdepth, Pixel>::TestSpeed(const int num_runs) {
+  if (blend_chroma_func_ == nullptr || blend_luma_func_ == nullptr) return;
+  ASSERT_TRUE(noise_image_[kPlaneY].Reset(height_,
+                                          width_ + kBorderPixelsFilmGrain,
+                                          /*zero_initialize=*/false));
+  ASSERT_TRUE(noise_image_[kPlaneU].Reset(uv_height_,
+                                          uv_width_ + kBorderPixelsFilmGrain,
+                                          /*zero_initialize=*/false));
+  ASSERT_TRUE(noise_image_[kPlaneV].Reset(uv_height_,
+                                          uv_width_ + kBorderPixelsFilmGrain,
+                                          /*zero_initialize=*/false));
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  // Allow any valid grain values.
+  const int grain_max = GetGrainMax<bitdepth>();
+  const int grain_min = GetGrainMin<bitdepth>();
+  const int random_range = grain_max - grain_min + 1;
+  auto* src_y = reinterpret_cast<Pixel*>(source_plane_y_);
+  auto* src_u = reinterpret_cast<Pixel*>(source_plane_u_);
+  auto* src_v = reinterpret_cast<Pixel*>(source_plane_v_);
+  for (int y = 0; y < height_; ++y) {
+    for (int x = 0; x < width_; ++x) {
+      const int random_source_y = rnd(random_range);
+      // Populating the luma source ensures the lookup table is tested. Chroma
+      // planes are given identical values. Giving them different values would
+      // artificially differentiate the outputs. It's important that the test
+      // expect that different outputs are caused by the different scaling
+      // lookup tables, rather than by different inputs.
+      const int uv_y_pos = y >> subsampling_y_;
+      const int uv_x_pos = x >> subsampling_x_;
+      src_y[y * width_ + x] = random_source_y;
+      src_u[uv_y_pos * uv_width_ + uv_x_pos] = random_source_y;
+      src_v[uv_y_pos * uv_width_ + uv_x_pos] = random_source_y;
+      const int random_y = rnd(random_range);
+      noise_image_[kPlaneY][y][x] = random_y + grain_min;
+      const int random_u = rnd(random_range);
+      noise_image_[kPlaneU][uv_y_pos][uv_x_pos] = random_u + grain_min;
+      const int random_v = rnd(random_range);
+      noise_image_[kPlaneV][uv_y_pos][uv_x_pos] = random_v + grain_min;
+    }
+  }
+  static constexpr int16_t kTestScalingLutY[kScalingLookupTableSize] = {
+      72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  72,  73,
+      75,  76,  77,  79,  80,  81,  83,  84,  86,  87,  88,  90,  91,  92,  92,
+      93,  93,  94,  95,  95,  96,  97,  97,  98,  98,  99,  99,  99,  99,  98,
+      98,  98,  98,  98,  98,  98,  97,  97,  97,  97,  97,  97,  97,  97,  97,
+      97,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+      99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  100, 100,
+      100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+      102, 102,
+  };
+  static constexpr int16_t kTestScalingLutU[kScalingLookupTableSize] = {
+      30,  42,  53,  65,  74,  74,  74,  74,  74,  74,  74,  74,  74,  74,  74,
+      75,  76,  78,  79,  81,  82,  83,  85,  86,  88,  89,  91,  92,  93,  93,
+      94,  94,  95,  95,  96,  96,  97,  97,  98,  98,  99,  99,  99,  99,  99,
+      99,  99,  99,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+      98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+      98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  99,  99,
+      99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,
+      99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,
+      99,  99,  99,  99,  99,  99,  100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+      110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      98,  98,  98,  98,  98,  98,  98,  97,  97,  97,  97,  97,  97,  97,  97,
+      97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  97,
+      97,  97,  97,  97,  97,  97,  97,  97,  97,  97,  96,  96,  96,  96,  96,
+      96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,
+      96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  96,  95,
+      95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,  95,
+      95,  95,
+  };
+  static constexpr int16_t kTestScalingLutV[kScalingLookupTableSize] = {
+      73,  73,  73,  73,  73,  73,  73,  73,  73,  73,  73,  73,  74,  74,  74,
+      75,  75,  78,  79,  81,  82,  83,  85,  86,  88,  89,  91,  92,  93,  93,
+      94,  94,  95,  95,  96,  96,  97,  97,  98,  98,  99,  99,  99,  99,  98,
+      98,  98,  98,  98,  98,  98,  97,  97,  97,  97,  97,  97,  97,  97,  97,
+      97,  97,  97,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,  98,
+      98,  98,  98,  98,  98,  99,  99,  99,  99,  99,  99,  99,  99,  99,  99,
+      99,  99,  99,  99,  99,  99,  100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
+      180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180,
+      200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
+      255, 255,
+  };
+
+  if (bitdepth == 10) {
+    for (int i = 0; i < kScalingLutBufferLength; ++i) {
+      ConvertScalingLut10bpp(scaling_lut_10bpp_y_, kTestScalingLutY);
+      ConvertScalingLut10bpp(scaling_lut_10bpp_u_, kTestScalingLutU);
+      ConvertScalingLut10bpp(scaling_lut_10bpp_v_, kTestScalingLutV);
+    }
+  }
+  const FilmGrainParams& params = kFilmGrainParams[0];
+  const int min_value = 16 << (bitdepth - 8);
+  const int max_value = 235 << (bitdepth - 8);
+  const absl::Time start = absl::Now();
+  for (int i = 0; i < num_runs; ++i) {
+    if (chroma_scaling_from_luma_) {
+      blend_chroma_func_(
+          kPlaneU, params, noise_image_, min_value, max_value, width_, height_,
+          /*start_height=*/0, subsampling_x_, subsampling_y_,
+          (bitdepth == 10) ? scaling_lut_10bpp_y_ : kTestScalingLutY,
+          source_plane_y_, y_stride_, source_plane_u_, uv_stride_,
+          dest_plane_u_, uv_stride_);
+      blend_chroma_func_(
+          kPlaneV, params, noise_image_, min_value, max_value, width_, height_,
+          /*start_height=*/0, subsampling_x_, subsampling_y_,
+          (bitdepth == 10) ? scaling_lut_10bpp_y_ : kTestScalingLutY,
+          source_plane_y_, y_stride_, source_plane_v_, uv_stride_,
+          dest_plane_v_, uv_stride_);
+    } else {
+      blend_chroma_func_(
+          kPlaneU, params, noise_image_, min_value, max_value, width_, height_,
+          /*start_height=*/0, subsampling_x_, subsampling_y_,
+          (bitdepth == 10) ? scaling_lut_10bpp_u_ : kTestScalingLutU,
+          source_plane_y_, y_stride_, source_plane_u_, uv_stride_,
+          dest_plane_u_, uv_stride_);
+      blend_chroma_func_(
+          kPlaneV, params, noise_image_, min_value, max_value, width_, height_,
+          /*start_height=*/0, subsampling_x_, subsampling_y_,
+          (bitdepth == 10) ? scaling_lut_10bpp_v_ : kTestScalingLutV,
+          source_plane_y_, y_stride_, source_plane_v_, uv_stride_,
+          dest_plane_v_, uv_stride_);
+    }
+    blend_luma_func_(noise_image_, min_value, max_value, params.chroma_scaling,
+                     width_, height_, /*start_height=*/0,
+                     (bitdepth == 10) ? scaling_lut_10bpp_y_ : kTestScalingLutY,
+                     source_plane_y_, y_stride_, dest_plane_y_, y_stride_);
+  }
+  const absl::Duration elapsed_time = absl::Now() - start;
+  const char* digest_luma = GetBlendLumaTestDigest(bitdepth);
+  printf("YBD%d \"%s\",\n", bitdepth,
+         test_utils::GetMd5Sum(dest_plane_y_, y_stride_ * height_).c_str());
+  printf("UBD%d \"%s\",\n", bitdepth,
+         test_utils::GetMd5Sum(dest_plane_u_, uv_stride_ * uv_height_).c_str());
+  printf("VBD%d \"%s\",\n", bitdepth,
+         test_utils::GetMd5Sum(dest_plane_v_, uv_stride_ * uv_height_).c_str());
+  test_utils::CheckMd5Digest(
+      "BlendNoiseWithImage",
+      absl::StrFormat("Luma cfl=%d, sub_x=%d, sub_y=%d",
+                      chroma_scaling_from_luma_, subsampling_x_, subsampling_y_)
+          .c_str(),
+      digest_luma, dest_plane_y_, y_stride_ * height_, elapsed_time);
+  const char* digest_chroma_u = GetBlendChromaUTestDigest(
+      bitdepth, chroma_scaling_from_luma_, subsampling_x_, subsampling_y_);
+  test_utils::CheckMd5Digest(
+      "BlendNoiseWithImage",
+      absl::StrFormat("ChromaU cfl=%d, sub_x=%d, sub_y=%d",
+                      chroma_scaling_from_luma_, subsampling_x_, subsampling_y_)
+          .c_str(),
+      digest_chroma_u, dest_plane_u_, uv_stride_ * uv_height_, elapsed_time);
+  const char* digest_chroma_v = GetBlendChromaVTestDigest(
+      bitdepth, chroma_scaling_from_luma_, subsampling_x_, subsampling_y_);
+  test_utils::CheckMd5Digest(
+      "BlendNoiseWithImage",
+      absl::StrFormat("ChromaV cfl=%d, sub_x=%d, sub_y=%d",
+                      chroma_scaling_from_luma_, subsampling_x_, subsampling_y_)
+          .c_str(),
+      digest_chroma_v, dest_plane_v_, uv_stride_ * uv_height_, elapsed_time);
+}
+
+using BlendNoiseTest8bpp = BlendNoiseTest<8, uint8_t>;
+
+TEST_P(BlendNoiseTest8bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(BlendNoiseTest8bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, BlendNoiseTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, BlendNoiseTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, BlendNoiseTest8bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using BlendNoiseTest10bpp = BlendNoiseTest<10, uint16_t>;
+
+TEST_P(BlendNoiseTest10bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(BlendNoiseTest10bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, BlendNoiseTest10bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, BlendNoiseTest10bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, BlendNoiseTest10bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using BlendNoiseTest12bpp = BlendNoiseTest<12, uint16_t>;
+
+TEST_P(BlendNoiseTest12bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(BlendNoiseTest12bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, BlendNoiseTest12bpp,
+                         testing::Combine(testing::Range(0, 2),
+                                          testing::Range(0, 3)));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+template <int bitdepth, typename Pixel>
+class FilmGrainSpeedTest : public testing::TestWithParam<int> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  FilmGrainSpeedTest() {
+    test_utils::ResetDspTable(bitdepth);
+    FilmGrainInit_C();
+
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    const char* const test_case = test_info->test_suite_name();
+    if (absl::StartsWith(test_case, "NEON/")) {
+#if LIBGAV1_ENABLE_NEON
+      FilmGrainInit_NEON();
+#endif
+    } else if (absl::StartsWith(test_case, "SSE41/")) {
+      FilmGrainInit_SSE4_1();
+    }
+    uv_width_ = (width_ + subsampling_x_) >> subsampling_x_;
+    uv_height_ = (height_ + subsampling_y_) >> subsampling_y_;
+    uv_stride_ = uv_width_ * sizeof(Pixel);
+    y_stride_ = width_ * sizeof(Pixel);
+    const size_t buffer_size =
+        sizeof(Pixel) * (width_ * height_ + 2 * uv_width_ * uv_height_);
+    source_buffer_.reset(new (std::nothrow) uint8_t[buffer_size]);
+    memset(source_buffer_.get(), 0, sizeof(source_buffer_[0]) * buffer_size);
+    dest_buffer_.reset(new (std::nothrow) uint8_t[buffer_size]);
+    memset(dest_buffer_.get(), 0, sizeof(dest_buffer_[0]) * buffer_size);
+    source_plane_y_ = source_buffer_.get();
+    source_plane_u_ = source_plane_y_ + y_stride_ * height_;
+    source_plane_v_ = source_plane_u_ + uv_stride_ * uv_height_;
+    dest_plane_y_ = dest_buffer_.get();
+    dest_plane_u_ = dest_plane_y_ + y_stride_ * height_;
+    dest_plane_v_ = dest_plane_u_ + uv_stride_ * uv_height_;
+    const int num_threads = GetParam();
+    thread_pool_ = ThreadPool::Create(num_threads);
+  }
+  ~FilmGrainSpeedTest() override = default;
+
+ protected:
+  void TestSpeed(int num_runs);
+
+ private:
+  const int width_ = 1920;
+  const int height_ = 1080;
+  const int subsampling_x_ = 1;
+  const int subsampling_y_ = 1;
+  int uv_width_ = 0;
+  int uv_height_ = 0;
+  int uv_stride_ = 0;
+  int y_stride_ = 0;
+  std::unique_ptr<uint8_t[]> source_buffer_;
+  std::unique_ptr<uint8_t[]> dest_buffer_;
+  const uint8_t* source_plane_y_ = nullptr;
+  const uint8_t* source_plane_u_ = nullptr;
+  const uint8_t* source_plane_v_ = nullptr;
+  uint8_t* dest_plane_y_ = nullptr;
+  uint8_t* dest_plane_u_ = nullptr;
+  uint8_t* dest_plane_v_ = nullptr;
+  std::unique_ptr<ThreadPool> thread_pool_;
+};
+
+// Each run of the speed test adds film grain noise to 10 dummy frames. The
+// film grain parameters for the 10 frames were generated with aomenc.
+template <int bitdepth, typename Pixel>
+void FilmGrainSpeedTest<bitdepth, Pixel>::TestSpeed(const int num_runs) {
+  const dsp::Dsp* dsp = GetDspTable(bitdepth);
+  if (dsp->film_grain.blend_noise_chroma[0] == nullptr ||
+      dsp->film_grain.blend_noise_luma == nullptr) {
+    return;
+  }
+  for (int k = 0; k < kNumFilmGrainTestParams; ++k) {
+    const FilmGrainParams& params = kFilmGrainParams[k];
+    const absl::Time start = absl::Now();
+    for (int i = 0; i < num_runs; ++i) {
+      FilmGrain<bitdepth> film_grain(params, /*is_monochrome=*/false,
+                                     /*color_matrix_is_identity=*/false,
+                                     subsampling_x_, subsampling_y_, width_,
+                                     height_, thread_pool_.get());
+      EXPECT_TRUE(film_grain.AddNoise(
+          source_plane_y_, y_stride_, source_plane_u_, source_plane_v_,
+          uv_stride_, dest_plane_y_, y_stride_, dest_plane_u_, dest_plane_v_,
+          uv_stride_));
+    }
+    const absl::Duration elapsed_time = absl::Now() - start;
+    const char* digest_luma = GetTestDigestLuma(bitdepth, k);
+    test_utils::CheckMd5Digest(
+        "FilmGrainSynthesisLuma",
+        absl::StrFormat("kFilmGrainParams[%d]", k).c_str(), digest_luma,
+        dest_plane_y_, y_stride_ * height_, elapsed_time);
+    const char* digest_chroma_u = GetTestDigestChromaU(bitdepth, k);
+    test_utils::CheckMd5Digest(
+        "FilmGrainSynthesisChromaU",
+        absl::StrFormat("kFilmGrainParams[%d]", k).c_str(), digest_chroma_u,
+        dest_plane_u_, uv_stride_ * uv_height_, elapsed_time);
+    const char* digest_chroma_v = GetTestDigestChromaV(bitdepth, k);
+    test_utils::CheckMd5Digest(
+        "FilmGrainSynthesisChromaV",
+        absl::StrFormat("kFilmGrainParams[%d]", k).c_str(), digest_chroma_v,
+        dest_plane_v_, uv_stride_ * uv_height_, elapsed_time);
+  }
+}
+
+using FilmGrainSpeedTest8bpp = FilmGrainSpeedTest<8, uint8_t>;
+
+TEST_P(FilmGrainSpeedTest8bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(FilmGrainSpeedTest8bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, FilmGrainSpeedTest8bpp, testing::Values(0, 3, 8));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, FilmGrainSpeedTest8bpp,
+                         testing::Values(0, 3, 8));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, FilmGrainSpeedTest8bpp,
+                         testing::Values(0, 3, 8));
+#endif
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using FilmGrainSpeedTest10bpp = FilmGrainSpeedTest<10, uint16_t>;
+
+TEST_P(FilmGrainSpeedTest10bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(FilmGrainSpeedTest10bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, FilmGrainSpeedTest10bpp, testing::Values(0, 3, 8));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, FilmGrainSpeedTest10bpp,
+                         testing::Values(0, 3, 8));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, FilmGrainSpeedTest10bpp,
+                         testing::Values(0, 3, 8));
+#endif
+
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using FilmGrainSpeedTest12bpp = FilmGrainSpeedTest<12, uint16_t>;
+
+TEST_P(FilmGrainSpeedTest12bpp, MatchesOriginalOutput) { TestSpeed(1); }
+
+TEST_P(FilmGrainSpeedTest12bpp, DISABLED_Speed) { TestSpeed(kNumSpeedTests); }
+
+INSTANTIATE_TEST_SUITE_P(C, FilmGrainSpeedTest12bpp, testing::Values(0, 3, 8));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+}  // namespace film_grain
+}  // namespace dsp
+}  // namespace libgav1
diff --git a/src/internal_frame_buffer_list_test.cc b/src/internal_frame_buffer_list_test.cc
new file mode 100644
index 0000000..21f1162
--- /dev/null
+++ b/src/internal_frame_buffer_list_test.cc
@@ -0,0 +1,158 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/internal_frame_buffer_list.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/gav1/frame_buffer.h"
+
+namespace libgav1 {
+namespace {
+
+class InternalFrameBufferListTest : public testing::Test {
+ protected:
+  static constexpr int kBufferListSize = 10;
+
+  InternalFrameBufferListTest() {
+    on_frame_buffer_size_changed_ = OnInternalFrameBufferSizeChanged;
+    get_frame_buffer_ = GetInternalFrameBuffer;
+    release_frame_buffer_ = ReleaseInternalFrameBuffer;
+    callback_private_data_ = &buffer_list_;
+  }
+
+  // Frame buffer callbacks.
+  FrameBufferSizeChangedCallback on_frame_buffer_size_changed_;
+  GetFrameBufferCallback get_frame_buffer_;
+  ReleaseFrameBufferCallback release_frame_buffer_;
+  // Private data associated with the frame buffer callbacks.
+  void* callback_private_data_;
+
+ private:
+  InternalFrameBufferList buffer_list_;
+};
+
+TEST_F(InternalFrameBufferListTest, ReleaseInRandomOrder) {
+  const int bitdepth = 8;
+  const Libgav1ImageFormat image_format = kLibgav1ImageFormatYuv420;
+  const int width = 100;
+  const int height = 50;
+  const int left_border = 0;
+  const int right_border = 0;
+  const int top_border = 0;
+  const int bottom_border = 0;
+  const int stride_alignment = 16;
+
+  EXPECT_EQ(on_frame_buffer_size_changed_(callback_private_data_, bitdepth,
+                                          image_format, width, height,
+                                          left_border, right_border, top_border,
+                                          bottom_border, stride_alignment),
+            0);
+
+  FrameBuffer frame_buffers[kBufferListSize];
+  for (auto& frame_buffer : frame_buffers) {
+    EXPECT_EQ(
+        get_frame_buffer_(callback_private_data_, bitdepth, image_format, width,
+                          height, left_border, right_border, top_border,
+                          bottom_border, stride_alignment, &frame_buffer),
+        0);
+    EXPECT_NE(frame_buffer.plane[0], nullptr);
+    EXPECT_GE(frame_buffer.stride[0], 112);
+    EXPECT_NE(frame_buffer.plane[1], nullptr);
+    EXPECT_GE(frame_buffer.stride[1], 64);
+    EXPECT_NE(frame_buffer.plane[2], nullptr);
+    EXPECT_GE(frame_buffer.stride[2], 64);
+  }
+
+  // Release and get a few buffers at indexes <= 5 in random order.
+  static_assert(5 < kBufferListSize, "");
+  static constexpr int indexes[] = {1, 4, 5, 5, 4, 3, 2, 3, 5, 0};
+  for (int index : indexes) {
+    release_frame_buffer_(callback_private_data_,
+                          frame_buffers[index].private_data);
+
+    EXPECT_EQ(get_frame_buffer_(callback_private_data_, bitdepth, image_format,
+                                width, height, left_border, right_border,
+                                top_border, bottom_border, stride_alignment,
+                                &frame_buffers[index]),
+              0);
+    EXPECT_NE(frame_buffers[index].plane[0], nullptr);
+    EXPECT_GE(frame_buffers[index].stride[0], 112);
+    EXPECT_NE(frame_buffers[index].plane[1], nullptr);
+    EXPECT_GE(frame_buffers[index].stride[1], 64);
+    EXPECT_NE(frame_buffers[index].plane[2], nullptr);
+    EXPECT_GE(frame_buffers[index].stride[2], 64);
+  }
+
+  for (auto& frame_buffer : frame_buffers) {
+    release_frame_buffer_(callback_private_data_, frame_buffer.private_data);
+  }
+}
+
+TEST_F(InternalFrameBufferListTest, VaryingBufferSizes) {
+  const int bitdepth = 8;
+  const Libgav1ImageFormat image_format = kLibgav1ImageFormatYuv420;
+  const int width = 64;
+  const int height = 48;
+  const int left_border = 16;
+  const int right_border = 16;
+  const int top_border = 16;
+  const int bottom_border = 16;
+  const int stride_alignment = 16;
+
+  EXPECT_EQ(on_frame_buffer_size_changed_(callback_private_data_, bitdepth,
+                                          image_format, 16 * width, 16 * height,
+                                          left_border, right_border, top_border,
+                                          bottom_border, stride_alignment),
+            0);
+
+  FrameBuffer frame_buffer;
+  for (int i = 1; i <= 16; ++i) {
+    EXPECT_EQ(get_frame_buffer_(callback_private_data_, bitdepth, image_format,
+                                i * width, i * height, left_border,
+                                right_border, top_border, bottom_border,
+                                stride_alignment, &frame_buffer),
+              0);
+    EXPECT_NE(frame_buffer.plane[0], nullptr);
+    EXPECT_GE(frame_buffer.stride[0], i * width + left_border + right_border);
+    EXPECT_NE(frame_buffer.plane[1], nullptr);
+    EXPECT_GE(frame_buffer.stride[1],
+              (i * width + left_border + right_border) >> 1);
+    EXPECT_NE(frame_buffer.plane[2], nullptr);
+    EXPECT_GE(frame_buffer.stride[2],
+              (i * width + left_border + right_border) >> 1);
+    release_frame_buffer_(callback_private_data_, frame_buffer.private_data);
+  }
+  for (int i = 16; i >= 1; --i) {
+    EXPECT_EQ(get_frame_buffer_(callback_private_data_, bitdepth, image_format,
+                                i * width, i * height, left_border,
+                                right_border, top_border, bottom_border,
+                                stride_alignment, &frame_buffer),
+              0);
+    EXPECT_NE(frame_buffer.plane[0], nullptr);
+    EXPECT_GE(frame_buffer.stride[0], i * width + left_border + right_border);
+    EXPECT_NE(frame_buffer.plane[1], nullptr);
+    EXPECT_GE(frame_buffer.stride[1],
+              (i * width + left_border + right_border) >> 1);
+    EXPECT_NE(frame_buffer.plane[2], nullptr);
+    EXPECT_GE(frame_buffer.stride[2],
+              (i * width + left_border + right_border) >> 1);
+    release_frame_buffer_(callback_private_data_, frame_buffer.private_data);
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/obu_parser_test.cc b/src/obu_parser_test.cc
new file mode 100644
index 0000000..a471037
--- /dev/null
+++ b/src/obu_parser_test.cc
@@ -0,0 +1,2677 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/obu_parser.h"
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <new>
+#include <string>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "src/buffer_pool.h"
+#include "src/decoder_impl.h"
+#include "src/decoder_state.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/gav1/status_code.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/dynamic_buffer.h"
+#include "src/utils/segmentation.h"
+#include "src/utils/types.h"
+#include "src/utils/vector.h"
+#include "tests/third_party/libvpx/acm_random.h"
+
+// Note the following test classes access private functions/members of
+// ObuParser. To be declared friends of ObuParser they must not have internal
+// linkage (they must be outside the anonymous namespace).
+namespace libgav1 {
+
+// Helper class to manipulate individual bits and generate a byte string.
+class BytesAndBits {
+ public:
+  // Append a bit to the end.
+  void AppendBit(uint8_t bit) { bits_.push_back(bit != 0); }
+
+  // Append a byte to the end.
+  void AppendByte(uint8_t byte) {
+    for (int i = 0; i < 8; ++i) {
+      AppendBit(GetNthBit(byte, i, 8));
+    }
+  }
+
+  // Append a literal of size |bits| to the end.
+  void AppendLiteral(int bits, int value) {
+    InsertLiteral(static_cast<int>(bits_.size()), bits, value);
+  }
+
+  // Append an inverse signed literal to the end. |bits + 1| bits are appended.
+  void AppendInverseSignedLiteral(int bits, int value) {
+    InsertInverseSignedLiteral(static_cast<int>(bits_.size()), bits, value);
+  }
+
+  // Append a sequence of bytes to the end.
+  void AppendBytes(const std::vector<uint8_t>& bytes) {
+    for (const auto& byte : bytes) {
+      AppendByte(byte);
+    }
+  }
+
+  // Insert |bit| in |offset|. Moves all other bits to the right by 1.
+  void InsertBit(int offset, uint8_t bit) {
+    auto iterator = bits_.begin();
+    bits_.insert(iterator + offset, bit != 0);
+  }
+
+  // Insert |value| of size |bits| at offset |offset|. Moves all other bits to
+  // the right by |bits|.
+  void InsertLiteral(int offset, int bits, int value) {
+    for (int i = 0; i < bits; ++i) {
+      InsertBit(i + offset, GetNthBit(value, i, bits));
+    }
+  }
+
+  // Insert |value| of size |bits| at offset |offset| as an inverse signed
+  // literal. Move all other bits to the right by |bits + 1|.
+  //
+  // Note: This is denoted su(1+bits) in the spec.
+  void InsertInverseSignedLiteral(int offset, int bits, int value) {
+    InsertBit(offset, (value >= 0) ? 0 : 1);
+    InsertLiteral(offset + 1, bits, value);
+  }
+
+  // Insert |value| at |offset| as an unsigned variable length code (uvlc).
+  // Return the number of bits inserted.
+  int InsertUvlc(int offset, int value) {
+    int leading_zeros = 1;
+    int shift_value = ++value;
+    while ((shift_value >>= 1) != 0) leading_zeros += 2;
+    int bits = 0;
+    InsertLiteral(offset, leading_zeros >> 1, 0);
+    bits += leading_zeros >> 1;
+    InsertLiteral(offset + bits, (leading_zeros + 1) >> 1, value);
+    bits += (leading_zeros + 1) >> 1;
+    return bits;
+  }
+
+  // Set the bit at |offset| to |bit|. The bit should already exist.
+  void SetBit(int offset, uint8_t bit) { bits_[offset] = bit != 0; }
+
+  // Set |bits| starting at |offset| to |value|. The bits should already exist.
+  void SetLiteral(int offset, int bits, int value) {
+    for (int i = 0; i < bits; ++i) {
+      SetBit(offset + i, GetNthBit(value, i, bits));
+    }
+  }
+
+  // Remove a bit in |offset|. Moves over all the following bits to the left by
+  // 1.
+  void RemoveBit(int offset) { RemoveLiteral(offset, 1); }
+
+  // Remove a literal of size |bits| from |offset|. Moves over all the
+  // following bits to the left by |bits|.
+  void RemoveLiteral(int offset, int bits) {
+    bits_.erase(bits_.begin() + offset, bits_.begin() + offset + bits);
+  }
+
+  // Remove all bits after offset.
+  void RemoveAllBitsAfter(int offset) {
+    RemoveLiteral(offset, static_cast<int>(bits_.size()) - offset);
+  }
+
+  // Clear all the bits stored.
+  void Clear() { bits_.clear(); }
+
+  // Generate the data vector from the bits. Pads 0 to the end of the last byte
+  // if necessary.
+  const std::vector<uint8_t>& GenerateData() {
+    data_.clear();
+    for (size_t i = 0; i < bits_.size(); i += 8) {
+      uint8_t byte = 0;
+      for (int j = 0; j < 8; ++j) {
+        const uint8_t bit =
+            ((i + j) < bits_.size()) ? static_cast<uint8_t>(bits_[i + j]) : 0;
+        byte |= bit << (7 - j);
+      }
+      data_.push_back(byte);
+    }
+    return data_;
+  }
+
+ private:
+  // Get the |n|th MSB from |value| with the assumption that |value| has |size|
+  // bits.
+  static uint8_t GetNthBit(int value, int n, int size) {
+    return (value >> (size - n - 1)) & 0x01;
+  }
+
+  std::vector<uint8_t> data_;
+  std::vector<bool> bits_;
+};
+
+class ObuParserTest : public testing::Test {
+ protected:
+  // Constants for unit tests.
+  static constexpr int kFrameWidthBits = 9;
+  static constexpr int kFrameHeightBits = 8;
+  static constexpr int kHeight = 240;
+  static constexpr int kWidth = 426;
+  static constexpr int kRows4x4 = 60;
+  static constexpr int kColumns4x4 = 108;
+  static constexpr int kFrameToShow = 2;
+  static constexpr int kDisplayFrameId = 10;
+  static constexpr int kFrameIdLengthBits = 15;
+  static constexpr int kDeltaFrameIdLengthBits = 14;
+
+  // Bit streams for testing. These may contain trailing bits and tests may have
+  // to remove some of the trailing bits to keep the boundary alignment.
+  const std::vector<uint8_t> kDefaultTemporalDelimiter = {0x12, 0x00};
+  // Bits  Syntax element                  Value
+  // 1     obu_forbidden_bit               0
+  // 4     obu_type                        2 (OBU_TEMPORAL_DELIMITER)
+  // 1     obu_extension_flag              1
+  // 1     obu_has_size_field              1
+  // 1     obu_reserved_1bit               0
+  // 3     temporal_id                     6
+  // 2     spatial_id                      2
+  // 3     extension_header_reserved_3bits 0
+  // 8     obu_size                        0
+  const std::vector<uint8_t> kDefaultTemporalDelimiterWithExtension = {
+      0x16, 0xd0, 0x00};
+  const std::vector<uint8_t> kDefaultHeaderWithoutSizeField = {0x10};
+  // Offset  Bits  Syntax element                     Value
+  // 0       3     seq_profile                        0
+  // 3       1     still_picture                      0
+  // 4       1     reduced_still_picture_header       0
+  // 5       1     timing_info_present_flag           0
+  // 6       1     initial_display_delay_present_flag 0
+  // 7       5     operating_points_cnt_minus_1       0
+  // 12      12    operating_point_idc[ 0 ]           0
+  // 24      5     seq_level_idx[ 0 ]                 0
+  // 29      4     frame_width_bits_minus_1           8
+  // 33      4     frame_height_bits_minus_1          7
+  // 37      9     max_frame_width_minus_1            425
+  // 46      8     max_frame_height_minus_1           239
+  // 54      1     frame_id_numbers_present_flag      0
+  // 55      1     use_128x128_superblock             1
+  // 56      1     enable_filter_intra                1
+  // 57      1     enable_intra_edge_filter           1
+  // 58      1     enable_interintra_compound         1
+  // 59      1     enable_masked_compound             1
+  // 60      1     enable_warped_motion               0
+  // 61      1     enable_dual_filter                 1
+  // 62      1     enable_order_hint                  1
+  // 63      1     enable_jnt_comp                    1
+  // 64      1     enable_ref_frame_mvs               1
+  // 65      1     seq_choose_screen_content_tools    1
+  // 66      1     seq_choose_integer_mv              1
+  // 67      3     order_hint_bits_minus_1            6
+  // 70      1     enable_superres                    0
+  // 71      1     enable_cdef                        1
+  // 72      1     enable_restoration                 1
+  // ...
+  const std::vector<uint8_t> kDefaultSequenceHeader = {
+      0x00, 0x00, 0x00, 0x04, 0x3e, 0xa7, 0xbd, 0xf7, 0xf9, 0x80, 0x40};
+  const std::vector<uint8_t> kDefaultFrameHeaderKeyFrame = {0x10, 0x00};
+  // Bits  Syntax element           Value
+  // 1     show_existing_frame      0
+  // 2     frame_type               2 (kFrameIntraOnly)
+  // 1     show_frame               1
+  // 1     error_resilient_mode     0
+  // 1     disable_cdf_update       0
+  // 1     frame_size_override_flag 0
+  // 8     refresh_frame_flags      4
+  // ...
+  const std::vector<uint8_t> kDefaultFrameHeaderIntraOnlyFrame = {0x50, 0x08,
+                                                                  0x00};
+  // Bits  Syntax element           Value
+  // 1     show_existing_frame      0
+  // 2     frame_type               1 (kFrameInter)
+  // 1     show_frame               1
+  // 1     error_resilient_mode     0
+  // 1     disable_cdf_update       0
+  // 1     frame_size_override_flag 0
+  // 3     primary_ref_frame        1
+  // 8     refresh_frame_flags      4
+  // 3     ref_frame_idx[0]         0
+  // 3     ref_frame_idx[1]         1
+  // 3     ref_frame_idx[2]         2
+  // 3     ref_frame_idx[3]         3
+  // 3     ref_frame_idx[4]         4
+  // 3     ref_frame_idx[5]         5
+  // 3     ref_frame_idx[6]         6
+  // ...
+  const std::vector<uint8_t> kDefaultFrameHeaderInterFrame = {0x30, 0x41, 0x01,
+                                                              0x4e, 0x5c, 0x60};
+  const std::vector<uint8_t> kDefaultGlobalMotionParametersRotZoom = {
+      0xff, 0x50, 0x77, 0x7e, 0x1f, 0xcd};
+  const std::vector<uint8_t> kDefaultGlobalMotionParametersAffine = {
+      0x3f, 0x50, 0x77, 0x7b, 0xbf, 0xa8, 0x3e, 0x1f, 0xcd};
+
+  void SetUp() override {
+    buffer_pool_.reset(new (std::nothrow)
+                           BufferPool(nullptr, nullptr, nullptr, nullptr));
+    ASSERT_NE(buffer_pool_, nullptr);
+  }
+
+  bool Init() {
+    obu_.reset(new (std::nothrow) ObuParser(nullptr, 0, 0, buffer_pool_.get(),
+                                            &decoder_state_));
+    if (obu_ == nullptr) return false;
+    obu_headers_ = &obu_->obu_headers_;
+    obu_frame_header_ = &obu_->frame_header_;
+    obu_sequence_header_ = &obu_->sequence_header_;
+    return true;
+  }
+
+  bool Init(const std::vector<uint8_t>& data, bool init_bit_reader = true) {
+    obu_.reset(new (std::nothrow) ObuParser(
+        data.data(), data.size(), 0, buffer_pool_.get(), &decoder_state_));
+    if (obu_ == nullptr) return false;
+    obu_headers_ = &obu_->obu_headers_;
+    obu_frame_header_ = &obu_->frame_header_;
+    obu_sequence_header_ = &obu_->sequence_header_;
+    return init_bit_reader ? obu_->InitBitReader(data.data(), data.size())
+                           : true;
+  }
+
+  bool Parse(const std::string& input,
+             const ObuSequenceHeader* const sequence_header = nullptr) {
+    std::vector<uint8_t> data(input.begin(), input.end());
+    return Parse(data, sequence_header);
+  }
+
+  bool Parse(const std::vector<uint8_t>& data,
+             const ObuSequenceHeader* const sequence_header = nullptr) {
+    EXPECT_TRUE(Init(data, false));
+    if (sequence_header != nullptr) obu_->set_sequence_header(*sequence_header);
+    return obu_->ParseOneFrame(&current_frame_) == kStatusOk;
+  }
+
+  bool ParseSequenceHeader(const std::vector<uint8_t>& data) {
+    EXPECT_TRUE(Init(data));
+    return obu_->ParseSequenceHeader(/*seen_frame_header=*/false);
+  }
+
+  bool ParseFrameParameters(const std::vector<uint8_t>& data,
+                            bool id_bits_present = false,
+                            int force_screen_content_tools = 0,
+                            int force_integer_mv = 0,
+                            bool enable_superres = false) {
+    EXPECT_TRUE(Init(data));
+    if (id_bits_present) {
+      obu_->sequence_header_.frame_id_numbers_present = true;
+      obu_->sequence_header_.frame_id_length_bits = kFrameIdLengthBits;
+      obu_->sequence_header_.delta_frame_id_length_bits =
+          kDeltaFrameIdLengthBits;
+    }
+    obu_->sequence_header_.force_screen_content_tools =
+        force_screen_content_tools;
+    obu_->sequence_header_.force_integer_mv = force_integer_mv;
+    obu_->sequence_header_.enable_superres = enable_superres;
+    obu_->sequence_header_.frame_width_bits = kFrameWidthBits;
+    obu_->sequence_header_.frame_height_bits = kFrameHeightBits;
+    obu_->sequence_header_.max_frame_width = kWidth;
+    obu_->sequence_header_.max_frame_height = kHeight;
+    return obu_->ParseFrameParameters();
+  }
+
+  bool ParseSegmentationParameters(const std::vector<uint8_t>& data,
+                                   int primary_reference_frame,
+                                   int prev_frame_index) {
+    EXPECT_TRUE(Init(data));
+    obu_->frame_header_.primary_reference_frame = primary_reference_frame;
+    if (primary_reference_frame != kPrimaryReferenceNone) {
+      obu_->frame_header_.reference_frame_index[primary_reference_frame] =
+          prev_frame_index;
+    }
+    return obu_->ParseSegmentationParameters();
+  }
+
+  bool ParseFrameReferenceModeSyntax(const std::vector<uint8_t>& data,
+                                     FrameType frame_type) {
+    EXPECT_TRUE(Init(data));
+    obu_->frame_header_.frame_type = frame_type;
+    return obu_->ParseFrameReferenceModeSyntax();
+  }
+
+  bool ParseGlobalMotionParameters(const std::vector<uint8_t>& data,
+                                   FrameType frame_type) {
+    EXPECT_TRUE(Init(data));
+    obu_->frame_header_.frame_type = frame_type;
+    obu_->frame_header_.primary_reference_frame = kPrimaryReferenceNone;
+    return obu_->ParseGlobalMotionParameters();
+  }
+
+  bool ParseFilmGrainParameters(const std::vector<uint8_t>& data,
+                                const ObuSequenceHeader& sequence_header,
+                                const ObuFrameHeader& frame_header) {
+    EXPECT_TRUE(Init(data));
+    obu_->set_sequence_header(sequence_header);
+    obu_->frame_header_ = frame_header;
+    return obu_->ParseFilmGrainParameters();
+  }
+
+  bool ParseTileInfoSyntax(const std::vector<uint8_t>& data, int columns4x4,
+                           int rows4x4, bool use_128x128_superblock) {
+    EXPECT_TRUE(Init(data));
+    obu_->frame_header_.columns4x4 = columns4x4;
+    obu_->frame_header_.rows4x4 = rows4x4;
+    obu_->sequence_header_.use_128x128_superblock = use_128x128_superblock;
+    return obu_->ParseTileInfoSyntax();
+  }
+
+  bool ParseMetadata(const std::vector<uint8_t>& data) {
+    EXPECT_TRUE(Init(data));
+    return obu_->ParseMetadata(data.data(), data.size());
+  }
+
+  void DefaultSequenceHeader(ObuSequenceHeader* const gold) {
+    memset(gold, 0, sizeof(*gold));
+    gold->profile = kProfile0;
+    gold->level[0].major = kMinimumMajorBitstreamLevel;
+    gold->operating_points = 1;
+    gold->max_frame_width = kWidth;
+    gold->max_frame_height = kHeight;
+    gold->frame_width_bits = kFrameWidthBits;
+    gold->frame_height_bits = kFrameHeightBits;
+    gold->use_128x128_superblock = true;
+    gold->enable_filter_intra = true;
+    gold->enable_intra_edge_filter = true;
+    gold->enable_interintra_compound = true;
+    gold->enable_masked_compound = true;
+    gold->enable_dual_filter = true;
+    gold->enable_order_hint = true;
+    gold->enable_jnt_comp = true;
+    gold->enable_ref_frame_mvs = true;
+    gold->choose_screen_content_tools = true;
+    gold->force_screen_content_tools = 2;
+    gold->choose_integer_mv = true;
+    gold->force_integer_mv = 2;
+    gold->order_hint_bits = 7;
+    gold->enable_cdef = true;
+    gold->enable_restoration = true;
+    gold->color_config.bitdepth = 8;
+    gold->color_config.color_primary = kColorPrimaryUnspecified;
+    gold->color_config.transfer_characteristics =
+        kTransferCharacteristicsUnspecified;
+    gold->color_config.matrix_coefficients = kMatrixCoefficientsUnspecified;
+    gold->color_config.subsampling_x = 1;
+    gold->color_config.subsampling_y = 1;
+  }
+
+  void DefaultFrameHeader(ObuFrameHeader* const gold, FrameType frame_type) {
+    memset(gold, 0, sizeof(*gold));
+    gold->frame_type = frame_type;
+    gold->show_frame = true;
+    gold->showable_frame = (frame_type != kFrameKey);
+    gold->enable_cdf_update = true;
+    gold->width = kWidth;
+    gold->height = kHeight;
+    gold->render_width = kWidth;
+    gold->render_height = kHeight;
+    gold->upscaled_width = kWidth;
+    gold->primary_reference_frame = kPrimaryReferenceNone;
+    gold->enable_frame_end_update_cdf = true;
+    gold->rows4x4 = kRows4x4;
+    gold->columns4x4 = kColumns4x4;
+    if (frame_type == kFrameKey) {
+      gold->refresh_frame_flags = 0xff;
+      gold->error_resilient_mode = true;
+      gold->force_integer_mv = 1;
+    } else if (frame_type == kFrameIntraOnly) {
+      gold->refresh_frame_flags = 4;
+      gold->force_integer_mv = 1;
+    } else if (frame_type == kFrameInter) {
+      gold->refresh_frame_flags = 4;
+      gold->primary_reference_frame = 1;
+      for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) {
+        gold->reference_frame_index[i] = i;
+      }
+      gold->is_motion_mode_switchable = true;
+    }
+  }
+
+  void OverrideFrameSize(BytesAndBits* const data, ObuFrameHeader* const gold,
+                         int flag_offset, int size_offset) {
+    data->SetBit(flag_offset, 1);  // frame_size_override_flag.
+    data->InsertLiteral(size_offset, kFrameWidthBits,
+                        kWidth - 2);  // frame_width_minus_1.
+    data->InsertLiteral(size_offset + kFrameWidthBits, kFrameHeightBits,
+                        kHeight - 2);  // frame_height_minus_1.
+    gold->frame_size_override_flag = true;
+    gold->width = kWidth - 1;
+    gold->height = kHeight - 1;
+    gold->render_width = gold->width;
+    gold->render_height = gold->height;
+    gold->upscaled_width = gold->width;
+  }
+
+  void OverrideRenderSize(BytesAndBits* const data, ObuFrameHeader* const gold,
+                          int flag_offset) {
+    data->SetBit(flag_offset, 1);  // render_and_frame_size_different.
+    data->InsertLiteral(flag_offset + 1, 16,
+                        kWidth - 10);  // render_width_minus_1.
+    data->InsertLiteral(flag_offset + 17, 16,
+                        kHeight - 10);  // render_height_minus_1.
+    gold->render_width = kWidth - 9;
+    gold->render_height = kHeight - 9;
+    gold->render_and_frame_size_different = true;
+  }
+
+  void OverrideSegmentation(BytesAndBits* const data, Segmentation* const gold,
+                            int offset) {
+    gold->update_data = true;
+    data->SetBit(offset++, static_cast<uint8_t>(gold->update_data));
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    gold->segment_id_pre_skip = false;
+    gold->last_active_segment_id = 0;
+    for (int i = 0; i < kMaxSegments; ++i) {
+      for (int j = 0; j < kSegmentFeatureMax; ++j) {
+        gold->feature_enabled[i][j] = static_cast<bool>(rnd.Rand8() & 1);
+        data->InsertBit(offset++,
+                        static_cast<uint8_t>(gold->feature_enabled[i][j]));
+        if (gold->feature_enabled[i][j]) {
+          gold->feature_data[i][j] = rnd(1 << kSegmentationFeatureBits[j]);
+          if (Segmentation::FeatureSigned(static_cast<SegmentFeature>(j))) {
+            if (static_cast<bool>(rnd.Rand8() & 1)) {
+              gold->feature_data[i][j] *= -1;
+            }
+            data->InsertInverseSignedLiteral(
+                offset, kSegmentationFeatureBits[j], gold->feature_data[i][j]);
+            offset += kSegmentationFeatureBits[j] + 1;
+          } else {
+            data->InsertLiteral(offset, kSegmentationFeatureBits[j],
+                                gold->feature_data[i][j]);
+            offset += kSegmentationFeatureBits[j];
+          }
+          gold->last_active_segment_id = i;
+          if (j >= kSegmentFeatureReferenceFrame) {
+            gold->segment_id_pre_skip = true;
+          }
+        }
+      }
+    }
+  }
+
+  void VerifyObuHeader(bool extension) {
+    EXPECT_EQ(obu_->obu_headers().back().temporal_id, extension ? 6 : 0);
+    EXPECT_EQ(obu_->obu_headers().back().spatial_id, extension ? 2 : 0);
+  }
+
+#define OBU_TEST_COMPARE(x) EXPECT_EQ(expected.x, actual.x)
+  void VerifyFrameParameters(const ObuFrameHeader& expected,
+                             bool id_bits_present = false) {
+    const ObuFrameHeader& actual = obu_->frame_header();
+    OBU_TEST_COMPARE(show_existing_frame);
+    if (actual.show_existing_frame) {
+      OBU_TEST_COMPARE(frame_to_show);
+      OBU_TEST_COMPARE(frame_presentation_time);
+      if (id_bits_present) {
+        OBU_TEST_COMPARE(display_frame_id);
+      }
+      return;
+    }
+    OBU_TEST_COMPARE(frame_type);
+    OBU_TEST_COMPARE(show_frame);
+    OBU_TEST_COMPARE(frame_presentation_time);
+    OBU_TEST_COMPARE(showable_frame);
+    OBU_TEST_COMPARE(error_resilient_mode);
+    OBU_TEST_COMPARE(enable_cdf_update);
+    OBU_TEST_COMPARE(current_frame_id);
+    OBU_TEST_COMPARE(frame_size_override_flag);
+    OBU_TEST_COMPARE(order_hint);
+    for (int i = 0; i < kNumReferenceFrameTypes; ++i) {
+      OBU_TEST_COMPARE(reference_order_hint[i]);
+    }
+    OBU_TEST_COMPARE(primary_reference_frame);
+    OBU_TEST_COMPARE(width);
+    OBU_TEST_COMPARE(height);
+    OBU_TEST_COMPARE(render_and_frame_size_different);
+    OBU_TEST_COMPARE(render_width);
+    OBU_TEST_COMPARE(render_height);
+    OBU_TEST_COMPARE(upscaled_width);
+    OBU_TEST_COMPARE(coded_lossless);
+    OBU_TEST_COMPARE(upscaled_lossless);
+    OBU_TEST_COMPARE(allow_screen_content_tools);
+    OBU_TEST_COMPARE(is_motion_mode_switchable);
+    OBU_TEST_COMPARE(refresh_frame_flags);
+    OBU_TEST_COMPARE(enable_frame_end_update_cdf);
+    OBU_TEST_COMPARE(force_integer_mv);
+    if (actual.frame_type == kFrameInter) {
+      for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) {
+        OBU_TEST_COMPARE(reference_frame_index[i]);
+      }
+    }
+    OBU_TEST_COMPARE(use_superres);
+    OBU_TEST_COMPARE(rows4x4);
+    OBU_TEST_COMPARE(columns4x4);
+  }
+
+  void VerifyLoopFilterParameters(const LoopFilter& expected) {
+    const LoopFilter& actual = obu_->frame_header().loop_filter;
+    for (int i = 0; i < 4; ++i) {
+      OBU_TEST_COMPARE(level[i]);
+    }
+    OBU_TEST_COMPARE(sharpness);
+    OBU_TEST_COMPARE(delta_enabled);
+    OBU_TEST_COMPARE(delta_update);
+    for (int i = 0; i < kNumReferenceFrameTypes; ++i) {
+      OBU_TEST_COMPARE(ref_deltas[i]);
+    }
+    for (int i = 0; i < kLoopFilterMaxModeDeltas; ++i) {
+      OBU_TEST_COMPARE(mode_deltas[i]);
+    }
+  }
+
+  void VerifyQuantizerParameters(const QuantizerParameters& expected) {
+    const QuantizerParameters& actual = obu_->frame_header().quantizer;
+    OBU_TEST_COMPARE(base_index);
+    OBU_TEST_COMPARE(delta_dc[kPlaneY]);
+    OBU_TEST_COMPARE(delta_dc[kPlaneU]);
+    OBU_TEST_COMPARE(delta_dc[kPlaneV]);
+    EXPECT_EQ(0, actual.delta_ac[kPlaneY]);
+    OBU_TEST_COMPARE(delta_ac[kPlaneY]);
+    OBU_TEST_COMPARE(delta_ac[kPlaneU]);
+    OBU_TEST_COMPARE(delta_ac[kPlaneV]);
+    OBU_TEST_COMPARE(use_matrix);
+    OBU_TEST_COMPARE(matrix_level[kPlaneY]);
+    OBU_TEST_COMPARE(matrix_level[kPlaneU]);
+    OBU_TEST_COMPARE(matrix_level[kPlaneV]);
+  }
+
+  void VerifySegmentationParameters(const Segmentation& expected) {
+    const Segmentation& actual = obu_->frame_header().segmentation;
+    OBU_TEST_COMPARE(enabled);
+    OBU_TEST_COMPARE(update_map);
+    OBU_TEST_COMPARE(update_data);
+    OBU_TEST_COMPARE(temporal_update);
+    OBU_TEST_COMPARE(segment_id_pre_skip);
+    OBU_TEST_COMPARE(last_active_segment_id);
+    for (int i = 0; i < kMaxSegments; ++i) {
+      for (int j = 0; j < kSegmentFeatureMax; ++j) {
+        OBU_TEST_COMPARE(feature_enabled[i][j]);
+        OBU_TEST_COMPARE(feature_data[i][j]);
+      }
+    }
+  }
+
+  void VerifyDeltaParameters(const Delta& expected, const Delta& actual) {
+    OBU_TEST_COMPARE(present);
+    OBU_TEST_COMPARE(scale);
+    OBU_TEST_COMPARE(multi);
+  }
+
+  void VerifyCdefParameters(const Cdef& expected) {
+    const Cdef& actual = obu_->frame_header().cdef;
+    OBU_TEST_COMPARE(damping);
+    OBU_TEST_COMPARE(bits);
+    for (int i = 0; i < (1 << actual.bits); ++i) {
+      OBU_TEST_COMPARE(y_primary_strength[i]);
+      OBU_TEST_COMPARE(y_secondary_strength[i]);
+      OBU_TEST_COMPARE(uv_primary_strength[i]);
+      OBU_TEST_COMPARE(uv_secondary_strength[i]);
+    }
+  }
+
+  void VerifyLoopRestorationParameters(const LoopRestoration& expected) {
+    const LoopRestoration& actual = obu_->frame_header().loop_restoration;
+    for (int i = 0; i < kMaxPlanes; ++i) {
+      OBU_TEST_COMPARE(type[i]);
+      OBU_TEST_COMPARE(unit_size_log2[i]);
+    }
+  }
+
+  void VerifyGlobalMotionParameters(
+      const std::array<GlobalMotion, kNumReferenceFrameTypes>& gold) {
+    for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) {
+      const GlobalMotion& expected = gold[i];
+      const GlobalMotion& actual = obu_->frame_header().global_motion[i];
+      OBU_TEST_COMPARE(type) << " i: " << i;
+      for (int j = 0; j < 6; ++j) {
+        OBU_TEST_COMPARE(params[j]) << " i: " << i << " j: " << j;
+      }
+    }
+  }
+
+  void VerifyFilmGrainParameters(const FilmGrainParams& expected) {
+    const FilmGrainParams& actual = obu_->frame_header().film_grain_params;
+    OBU_TEST_COMPARE(apply_grain);
+    OBU_TEST_COMPARE(update_grain);
+    OBU_TEST_COMPARE(chroma_scaling_from_luma);
+    OBU_TEST_COMPARE(overlap_flag);
+    OBU_TEST_COMPARE(clip_to_restricted_range);
+    OBU_TEST_COMPARE(num_y_points);
+    OBU_TEST_COMPARE(num_u_points);
+    OBU_TEST_COMPARE(num_v_points);
+    for (int i = 0; i < 14; ++i) {
+      OBU_TEST_COMPARE(point_y_value[i]);
+      OBU_TEST_COMPARE(point_y_scaling[i]);
+    }
+    for (int i = 0; i < 10; ++i) {
+      OBU_TEST_COMPARE(point_u_value[i]);
+      OBU_TEST_COMPARE(point_u_scaling[i]);
+    }
+    for (int i = 0; i < 10; ++i) {
+      OBU_TEST_COMPARE(point_v_value[i]);
+      OBU_TEST_COMPARE(point_v_scaling[i]);
+    }
+    OBU_TEST_COMPARE(chroma_scaling);
+    OBU_TEST_COMPARE(auto_regression_coeff_lag);
+    for (int i = 0; i < 24; ++i) {
+      OBU_TEST_COMPARE(auto_regression_coeff_y[i]);
+    }
+    for (int i = 0; i < 25; ++i) {
+      OBU_TEST_COMPARE(auto_regression_coeff_u[i]);
+    }
+    for (int i = 0; i < 25; ++i) {
+      OBU_TEST_COMPARE(auto_regression_coeff_v[i]);
+    }
+    OBU_TEST_COMPARE(auto_regression_shift);
+    OBU_TEST_COMPARE(grain_seed);
+    OBU_TEST_COMPARE(reference_index);
+    OBU_TEST_COMPARE(grain_scale_shift);
+    OBU_TEST_COMPARE(u_multiplier);
+    OBU_TEST_COMPARE(u_luma_multiplier);
+    OBU_TEST_COMPARE(u_offset);
+    OBU_TEST_COMPARE(v_multiplier);
+    OBU_TEST_COMPARE(v_luma_multiplier);
+    OBU_TEST_COMPARE(v_offset);
+  }
+
+  void VerifyTileInfoParameters(const TileInfo& expected) {
+    const TileInfo& actual = obu_->frame_header().tile_info;
+    OBU_TEST_COMPARE(uniform_spacing);
+    OBU_TEST_COMPARE(tile_columns_log2);
+    OBU_TEST_COMPARE(tile_columns);
+    for (int i = 0; i < kMaxTileColumns + 1; ++i) {
+      OBU_TEST_COMPARE(tile_column_start[i]) << "tile_column: " << i;
+      OBU_TEST_COMPARE(tile_column_width_in_superblocks[i])
+          << "tile_column: " << i;
+    }
+    OBU_TEST_COMPARE(tile_rows_log2);
+    OBU_TEST_COMPARE(tile_rows);
+    for (int i = 0; i < kMaxTileRows + 1; ++i) {
+      OBU_TEST_COMPARE(tile_row_start[i]) << "tile_row: " << i;
+      OBU_TEST_COMPARE(tile_row_height_in_superblocks[i]) << "tile_rows: " << i;
+    }
+    OBU_TEST_COMPARE(tile_count);
+    OBU_TEST_COMPARE(context_update_id);
+    OBU_TEST_COMPARE(tile_size_bytes);
+  }
+
+  void VerifySequenceHeader(const ObuSequenceHeader& expected) {
+    EXPECT_TRUE(obu_->sequence_header_changed());
+    const ObuSequenceHeader& actual = obu_->sequence_header();
+    OBU_TEST_COMPARE(profile);
+    OBU_TEST_COMPARE(still_picture);
+    OBU_TEST_COMPARE(reduced_still_picture_header);
+    OBU_TEST_COMPARE(operating_points);
+    for (int i = 0; i < actual.operating_points; ++i) {
+      OBU_TEST_COMPARE(operating_point_idc[i]) << "i: " << i;
+      OBU_TEST_COMPARE(level[i].major) << "i: " << i;
+      OBU_TEST_COMPARE(level[i].minor) << "i: " << i;
+      OBU_TEST_COMPARE(tier[i]) << "i: " << i;
+    }
+    OBU_TEST_COMPARE(frame_width_bits);
+    OBU_TEST_COMPARE(frame_height_bits);
+    OBU_TEST_COMPARE(max_frame_width);
+    OBU_TEST_COMPARE(max_frame_height);
+    OBU_TEST_COMPARE(frame_id_numbers_present);
+    if (actual.frame_id_numbers_present) {
+      OBU_TEST_COMPARE(frame_id_length_bits);
+      OBU_TEST_COMPARE(delta_frame_id_length_bits);
+    }
+    OBU_TEST_COMPARE(use_128x128_superblock);
+    OBU_TEST_COMPARE(enable_filter_intra);
+    OBU_TEST_COMPARE(enable_intra_edge_filter);
+    OBU_TEST_COMPARE(enable_interintra_compound);
+    OBU_TEST_COMPARE(enable_masked_compound);
+    OBU_TEST_COMPARE(enable_warped_motion);
+    OBU_TEST_COMPARE(enable_dual_filter);
+    OBU_TEST_COMPARE(enable_order_hint);
+    OBU_TEST_COMPARE(enable_jnt_comp);
+    OBU_TEST_COMPARE(enable_ref_frame_mvs);
+    OBU_TEST_COMPARE(choose_screen_content_tools);
+    OBU_TEST_COMPARE(force_screen_content_tools);
+    OBU_TEST_COMPARE(choose_integer_mv);
+    OBU_TEST_COMPARE(force_integer_mv);
+    OBU_TEST_COMPARE(order_hint_bits);
+    OBU_TEST_COMPARE(enable_superres);
+    OBU_TEST_COMPARE(enable_cdef);
+    OBU_TEST_COMPARE(enable_restoration);
+    OBU_TEST_COMPARE(color_config.bitdepth);
+    OBU_TEST_COMPARE(color_config.is_monochrome);
+    OBU_TEST_COMPARE(color_config.color_range);
+    OBU_TEST_COMPARE(color_config.subsampling_x);
+    OBU_TEST_COMPARE(color_config.subsampling_y);
+    OBU_TEST_COMPARE(color_config.chroma_sample_position);
+    OBU_TEST_COMPARE(timing_info_present_flag);
+    OBU_TEST_COMPARE(timing_info.num_units_in_tick);
+    OBU_TEST_COMPARE(timing_info.time_scale);
+    OBU_TEST_COMPARE(timing_info.equal_picture_interval);
+    OBU_TEST_COMPARE(timing_info.num_ticks_per_picture);
+    OBU_TEST_COMPARE(decoder_model_info_present_flag);
+    OBU_TEST_COMPARE(decoder_model_info.encoder_decoder_buffer_delay_length);
+    OBU_TEST_COMPARE(decoder_model_info.num_units_in_decoding_tick);
+    OBU_TEST_COMPARE(decoder_model_info.buffer_removal_time_length);
+    OBU_TEST_COMPARE(decoder_model_info.frame_presentation_time_length);
+    for (int i = 0; i < actual.operating_points; ++i) {
+      SCOPED_TRACE("i: " + std::to_string(i));
+      OBU_TEST_COMPARE(operating_parameters.decoder_buffer_delay[i]);
+      OBU_TEST_COMPARE(operating_parameters.encoder_buffer_delay[i]);
+      OBU_TEST_COMPARE(operating_parameters.low_delay_mode_flag[i]);
+      OBU_TEST_COMPARE(initial_display_delay[i]);
+    }
+    OBU_TEST_COMPARE(film_grain_params_present);
+  }
+
+  void VerifyMetadataHdrCll(const ObuMetadataHdrCll& expected) {
+    EXPECT_TRUE(obu_->current_frame_->hdr_cll_set());
+    const ObuMetadataHdrCll& actual = obu_->current_frame_->hdr_cll();
+    OBU_TEST_COMPARE(max_cll);
+    OBU_TEST_COMPARE(max_fall);
+  }
+
+  void VerifyMetadataHdrMdcv(const ObuMetadataHdrMdcv& expected) {
+    EXPECT_TRUE(obu_->current_frame_->hdr_mdcv_set());
+    const ObuMetadataHdrMdcv& actual = obu_->current_frame_->hdr_mdcv();
+    for (int i = 0; i < 3; ++i) {
+      OBU_TEST_COMPARE(primary_chromaticity_x[i]);
+      OBU_TEST_COMPARE(primary_chromaticity_y[i]);
+    }
+    OBU_TEST_COMPARE(white_point_chromaticity_x);
+    OBU_TEST_COMPARE(white_point_chromaticity_y);
+    OBU_TEST_COMPARE(luminance_max);
+    OBU_TEST_COMPARE(luminance_min);
+  }
+
+  void VerifyMetadataItutT35(const ObuMetadataItutT35& expected) {
+    EXPECT_TRUE(obu_->current_frame_->itut_t35_set());
+    const ObuMetadataItutT35& actual = obu_->current_frame_->itut_t35();
+    OBU_TEST_COMPARE(country_code);
+    if (actual.country_code == 0xFF) {
+      OBU_TEST_COMPARE(country_code_extension_byte);
+    }
+    ASSERT_EQ(expected.payload_size, actual.payload_size);
+    if (actual.payload_size != 0) {
+      EXPECT_EQ(memcmp(expected.payload_bytes, actual.payload_bytes,
+                       actual.payload_size),
+                0);
+    }
+  }
+
+#undef OBU_TEST_COMPARE
+
+  // Accessors to private members of ObuParser. This avoids the need for a
+  // dependency on a googletest header in the main library for FRIEND_TEST()
+  // (or the need to duplicate the implementation).
+  bool ObuParseFrameParameters() { return obu_->ParseFrameParameters(); }
+  bool ObuParseLoopFilterParameters() {
+    return obu_->ParseLoopFilterParameters();
+  }
+  bool ObuParseLoopFilterDeltaParameters() {
+    return obu_->ParseLoopFilterDeltaParameters();
+  }
+  bool ObuParseQuantizerParameters() {
+    return obu_->ParseQuantizerParameters();
+  }
+  bool ObuParseQuantizerIndexDeltaParameters() {
+    return obu_->ParseQuantizerIndexDeltaParameters();
+  }
+  void ObuComputeSegmentLosslessAndQIndex() {
+    obu_->ComputeSegmentLosslessAndQIndex();
+  }
+  bool ObuParseCdefParameters() { return obu_->ParseCdefParameters(); }
+  bool ObuParseLoopRestorationParameters() {
+    return obu_->ParseLoopRestorationParameters();
+  }
+  bool ObuParseTxModeSyntax() { return obu_->ParseTxModeSyntax(); }
+  bool ObuIsSkipModeAllowed() { return obu_->IsSkipModeAllowed(); }
+  bool ObuParseSkipModeParameters() { return obu_->ParseSkipModeParameters(); }
+  bool ObuReadAllowWarpedMotion() { return obu_->ReadAllowWarpedMotion(); }
+  bool ObuSetFrameReferences(int8_t last_frame_idx, int8_t gold_frame_idx) {
+    return obu_->SetFrameReferences(last_frame_idx, gold_frame_idx);
+  }
+
+  std::unique_ptr<BufferPool> buffer_pool_;
+  DecoderState decoder_state_;
+  std::unique_ptr<ObuParser> obu_;
+  // The following members are reset with each Init().
+  Vector<ObuHeader>* obu_headers_;
+  ObuFrameHeader* obu_frame_header_;
+  ObuSequenceHeader* obu_sequence_header_;
+  RefCountedBufferPtr current_frame_;
+};
+
+TEST_F(ObuParserTest, InvalidInputs) {
+  obu_.reset(new (std::nothrow)
+                 ObuParser(nullptr, 0, 0, buffer_pool_.get(), &decoder_state_));
+  EXPECT_EQ(obu_->ParseOneFrame(&current_frame_), kStatusInvalidArgument);
+  obu_.reset(new (std::nothrow) ObuParser(nullptr, 10, 0, buffer_pool_.get(),
+                                          &decoder_state_));
+  EXPECT_EQ(obu_->ParseOneFrame(&current_frame_), kStatusInvalidArgument);
+  obu_.reset(new (std::nothrow)
+                 ObuParser(kDefaultTemporalDelimiter.data(), 0, 0,
+                           buffer_pool_.get(), &decoder_state_));
+  EXPECT_EQ(obu_->ParseOneFrame(&current_frame_), kStatusInvalidArgument);
+}
+
+TEST_F(ObuParserTest, TemporalDelimiter) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultTemporalDelimiter);
+
+  ASSERT_TRUE(Parse(data.GenerateData()));
+  EXPECT_EQ(obu_->obu_headers().size(), 1);
+  EXPECT_EQ(obu_->obu_headers().back().type, kObuTemporalDelimiter);
+  VerifyObuHeader(false);
+
+  // forbidden_bit is not zero.
+  data.SetBit(0, 1);
+  EXPECT_FALSE(Parse(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, HeaderExtensions) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultTemporalDelimiterWithExtension);
+
+  ASSERT_TRUE(Parse(data.GenerateData()));
+  EXPECT_EQ(obu_->obu_headers().size(), 1);
+  EXPECT_EQ(obu_->obu_headers().back().type, kObuTemporalDelimiter);
+  VerifyObuHeader(true);
+
+  // extension flag is set but no extensions found.
+  data.Clear();
+  data.AppendByte(kDefaultTemporalDelimiterWithExtension[0]);
+  EXPECT_FALSE(Parse(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, HeaderHasSizeFieldNotSet) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultHeaderWithoutSizeField);
+
+  EXPECT_FALSE(Parse(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, SequenceHeader) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderLevel) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  // Set level to 1.
+  gold.level[0].major = 2;
+  gold.level[0].minor = 1;
+  data.SetLiteral(24, 5, 1);  // level.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  // Set operating_point_idc of operating point 1 to 0x101 (temporal layer 0
+  // and spatial layer 0 should be decoded). Set level of operating point 1 to
+  // 8 (4.0) and tier to 1.
+  gold.operating_points = 2;
+  gold.operating_point_idc[1] = (1 << 0) | (1 << (0 + 8));
+  gold.level[1].major = 4;
+  gold.level[1].minor = 0;
+  gold.tier[1] = 1;
+  data.SetLiteral(7, 5, gold.operating_points - 1);
+  data.InsertLiteral(29, 12, 0x101);  // operating_point_idc.
+  data.InsertLiteral(41, 5, 8);       // level.
+  data.InsertBit(46, gold.tier[1]);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderProfile) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.still_picture = true;
+  data.SetBit(3, static_cast<uint8_t>(gold.still_picture));
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  // profile 2; bitdepth 8;
+  gold.profile = kProfile2;
+  gold.color_config.bitdepth = 8;
+  gold.color_config.subsampling_x = 1;
+  gold.color_config.subsampling_y = 0;
+  data.SetLiteral(0, 3, gold.profile);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  // profile 2; bitdepth 10;
+  gold.color_config.bitdepth = 10;
+  data.SetBit(73, 1);     // high_bitdepth.
+  data.InsertBit(74, 0);  // twelve_bit.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  // profile 2; bitdepth 12;
+  gold.color_config.bitdepth = 12;
+  gold.color_config.subsampling_y = 1;
+  data.SetBit(74, 1);     // twelve_bit.
+  data.InsertBit(78, 1);  // subsampling_x.
+  data.InsertBit(79, 1);  // subsampling_y.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderIdLength) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.frame_id_numbers_present = true;
+  gold.delta_frame_id_length_bits = kDeltaFrameIdLengthBits;
+  gold.frame_id_length_bits = kFrameIdLengthBits;
+  data.SetBit(54, 1);  // frame_id_numbers_present.
+  data.InsertLiteral(55, 4, kDeltaFrameIdLengthBits - 2);
+  data.InsertLiteral(59, 3, kFrameIdLengthBits - kDeltaFrameIdLengthBits - 1);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+// An idLen greater than 16 is invalid.
+TEST_F(ObuParserTest, SequenceHeaderIdLengthInvalid) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+
+  data.SetBit(54, 1);  // frame_id_numbers_present.
+  data.InsertLiteral(55, 4, kDeltaFrameIdLengthBits - 2);
+  data.InsertLiteral(59, 3, 17 - kDeltaFrameIdLengthBits - 1);  // idLen = 17.
+
+  ASSERT_FALSE(ParseSequenceHeader(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, SequenceHeaderFlags) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.enable_warped_motion = true;
+  gold.enable_superres = true;
+  data.SetBit(60, 1);  // enable_warped_motion.
+  data.SetBit(70, 1);  // enable_superres.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderForceScreenContentToolsEqualTo0) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.choose_screen_content_tools = false;
+  gold.force_screen_content_tools = 0;
+  gold.choose_integer_mv = false;
+  gold.force_integer_mv = 2;
+  data.SetBit(65, 0);  // choose_screen_content_tools.
+  data.SetBit(66, 0);  // force_screen_content_tools.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderMonochrome) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.color_config.is_monochrome = true;
+  gold.color_config.color_range = kColorRangeFull;
+  data.SetBit(74, 1);     // monochrome.
+  data.InsertBit(76, 1);  // color_range.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+// This tests TimingInfo, DecoderModelInfo and OperatingParameters. The test is
+// kind of long but it is the simplest way to test all three since they are
+// dependent on one another.
+TEST_F(ObuParserTest, SequenceHeaderTimingInfo) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.timing_info_present_flag = true;
+  gold.timing_info.num_units_in_tick = 100;
+  gold.timing_info.time_scale = 1000;
+  gold.timing_info.equal_picture_interval = false;
+  gold.decoder_model_info_present_flag = false;
+  data.SetBit(5, static_cast<uint8_t>(gold.timing_info_present_flag));
+  data.InsertLiteral(6, 32, gold.timing_info.num_units_in_tick);
+  data.InsertLiteral(38, 32, gold.timing_info.time_scale);
+  data.InsertBit(70,
+                 static_cast<uint8_t>(gold.timing_info.equal_picture_interval));
+  data.InsertBit(71,
+                 static_cast<uint8_t>(gold.decoder_model_info_present_flag));
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  gold.timing_info.equal_picture_interval = true;
+  gold.timing_info.num_ticks_per_picture = 7;
+  data.SetBit(70,
+              static_cast<uint8_t>(gold.timing_info.equal_picture_interval));
+  EXPECT_EQ(data.InsertUvlc(71, gold.timing_info.num_ticks_per_picture - 1), 5);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  gold.decoder_model_info_present_flag = true;
+  gold.decoder_model_info.encoder_decoder_buffer_delay_length = 5;
+  gold.decoder_model_info.num_units_in_decoding_tick = 1000;
+  gold.decoder_model_info.buffer_removal_time_length = 18;
+  gold.decoder_model_info.frame_presentation_time_length = 20;
+
+  data.SetBit(76, static_cast<uint8_t>(gold.decoder_model_info_present_flag));
+  data.InsertLiteral(
+      77, 5, gold.decoder_model_info.encoder_decoder_buffer_delay_length - 1);
+  data.InsertLiteral(82, 32,
+                     gold.decoder_model_info.num_units_in_decoding_tick);
+  data.InsertLiteral(114, 5,
+                     gold.decoder_model_info.buffer_removal_time_length - 1);
+  data.InsertLiteral(
+      119, 5, gold.decoder_model_info.frame_presentation_time_length - 1);
+  data.InsertBit(147, 0);  // decoder_model_present_for_this_op.
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+
+  gold.operating_parameters.decoder_buffer_delay[0] = 10;
+  gold.operating_parameters.encoder_buffer_delay[0] = 20;
+  gold.operating_parameters.low_delay_mode_flag[0] = true;
+
+  data.SetBit(147, 1);  // decoder_model_present_for_this_op.
+  data.InsertLiteral(
+      148, gold.decoder_model_info.encoder_decoder_buffer_delay_length,
+      gold.operating_parameters.decoder_buffer_delay[0]);
+  data.InsertLiteral(
+      153, gold.decoder_model_info.encoder_decoder_buffer_delay_length,
+      gold.operating_parameters.encoder_buffer_delay[0]);
+  data.InsertBit(158, static_cast<uint8_t>(
+                          gold.operating_parameters.low_delay_mode_flag[0]));
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+TEST_F(ObuParserTest, SequenceHeaderInitialDisplayDelay) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultSequenceHeader);
+  ObuSequenceHeader gold;
+  DefaultSequenceHeader(&gold);
+
+  gold.initial_display_delay[0] = 8;
+
+  data.SetBit(6, 1);      // initial_display_delay_present_flag.
+  data.InsertBit(29, 1);  // initial_display_delay_present_for_this_op.
+  data.InsertLiteral(30, 4, gold.initial_display_delay[0] - 1);
+
+  ASSERT_TRUE(ParseSequenceHeader(data.GenerateData()));
+  VerifySequenceHeader(gold);
+}
+
+// Parsing of a frame header should fail if no sequence header has been
+// received.
+TEST_F(ObuParserTest, FrameHeaderWithoutSequenceHeader) {
+  // The aom-test-data test vector av1-1-b8-01-size-16x16.ivf has two temporal
+  // units. The first temporal unit has a presentation timestamp of 0 and
+  // consists of three OBUs: a temporal delimiter OBU, a sequence header OBU,
+  // and a frame OBU.
+  const std::vector<uint8_t> kTemporalDelimiter = {0x12, 0x00};
+  const std::vector<uint8_t> kSequenceHeader = {
+      0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x9f, 0xfb, 0xff, 0xf3, 0x00, 0x80};
+  const std::vector<uint8_t> kFrame = {
+      0x32, 0xa6, 0x01, 0x10, 0x00, 0x87, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00,
+      0x40, 0x00, 0x9e, 0x86, 0x5b, 0xb2, 0x22, 0xb5, 0x58, 0x4d, 0x68, 0xe6,
+      0x37, 0x54, 0x42, 0x7b, 0x84, 0xce, 0xdf, 0x9f, 0xec, 0xab, 0x07, 0x4d,
+      0xf6, 0xe1, 0x5e, 0x9e, 0x27, 0xbf, 0x93, 0x2f, 0x47, 0x0d, 0x7b, 0x7c,
+      0x45, 0x8d, 0xcf, 0x26, 0xf7, 0x6c, 0x06, 0xd7, 0x8c, 0x2e, 0xf5, 0x2c,
+      0xb0, 0x8a, 0x31, 0xac, 0x69, 0xf5, 0xcd, 0xd8, 0x71, 0x5d, 0xaf, 0xf8,
+      0x96, 0x43, 0x8c, 0x9c, 0x23, 0x6f, 0xab, 0xd0, 0x35, 0x43, 0xdf, 0x81,
+      0x12, 0xe3, 0x7d, 0xec, 0x22, 0xb0, 0x30, 0x54, 0x32, 0x9f, 0x90, 0xc0,
+      0x5d, 0x64, 0x9b, 0x0f, 0x75, 0x31, 0x84, 0x3a, 0x57, 0xd7, 0x5f, 0x03,
+      0x6e, 0x7f, 0x43, 0x17, 0x6d, 0x08, 0xc3, 0x81, 0x8a, 0xae, 0x73, 0x1c,
+      0xa8, 0xa7, 0xe4, 0x9c, 0xa9, 0x5b, 0x3f, 0xd1, 0xeb, 0x75, 0x3a, 0x7f,
+      0x22, 0x77, 0x38, 0x64, 0x1c, 0x77, 0xdb, 0xcd, 0xef, 0xb7, 0x08, 0x45,
+      0x8e, 0x7f, 0xea, 0xa3, 0xd0, 0x81, 0xc9, 0xc1, 0xbc, 0x93, 0x9b, 0x41,
+      0xb1, 0xa1, 0x42, 0x17, 0x98, 0x3f, 0x1e, 0x95, 0xdf, 0x68, 0x7c, 0xb7,
+      0x98};
+
+  BytesAndBits data;
+  data.AppendBytes(kTemporalDelimiter);
+  // Skip the sequence header OBU.
+  data.AppendBytes(kFrame);
+  ASSERT_FALSE(Parse(data.GenerateData()));
+
+  // Now verify that all three OBUs are correct, by adding them to |data|
+  // successively.
+  data.Clear();
+  data.AppendBytes(kTemporalDelimiter);
+  ASSERT_TRUE(Parse(data.GenerateData()));
+  data.Clear();
+  data.AppendBytes(kTemporalDelimiter);
+  data.AppendBytes(kSequenceHeader);
+  ASSERT_TRUE(Parse(data.GenerateData()));
+  data.Clear();
+  data.AppendBytes(kTemporalDelimiter);
+  data.AppendBytes(kSequenceHeader);
+  data.AppendBytes(kFrame);
+  ASSERT_TRUE(Parse(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, FrameParameterShowExistingFrame) {
+  BytesAndBits data;
+  data.AppendBit(1);                    // show_existing_frame.
+  data.AppendLiteral(3, kFrameToShow);  // frame_to_show.
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+  gold.show_existing_frame = true;
+  gold.frame_to_show = kFrameToShow;
+
+  // kFrameToShow'th frame is not yet decoded.
+  ASSERT_FALSE(ParseFrameParameters(data.GenerateData()));
+
+  decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer();
+  // kFrameToShow'th frame is not a showable frame.
+  ASSERT_FALSE(ParseFrameParameters(data.GenerateData()));
+
+  decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true);
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParametersShowExistingFrameWithDisplayFrameId) {
+  BytesAndBits data;
+  data.AppendBit(1);                        // show_existing_frame.
+  data.AppendLiteral(3, kFrameToShow);      // frame_to_show.
+  data.AppendLiteral(15, kDisplayFrameId);  // display_frame_id.
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+  gold.show_existing_frame = true;
+  gold.frame_to_show = kFrameToShow;
+  gold.display_frame_id = kDisplayFrameId;
+
+  // kFrameToShow'th frame is not yet decoded.
+  ASSERT_FALSE(ParseFrameParameters(data.GenerateData(), true));
+
+  decoder_state_.reference_frame_id[kFrameToShow] = kDisplayFrameId;
+  decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer();
+  // kFrameToShow'th frame is not a showable frame.
+  ASSERT_FALSE(ParseFrameParameters(data.GenerateData(), true));
+
+  decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true);
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), true));
+  VerifyFrameParameters(gold, true);
+}
+
+TEST_F(ObuParserTest, FrameParameterShowExistingFrameTemporalPointInfo) {
+  BytesAndBits data;
+  data.AppendBit(1);                    // show_existing_frame.
+  data.AppendLiteral(3, kFrameToShow);  // frame_to_show.
+  data.AppendLiteral(20, 38);           // frame_presentation_time.
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+  gold.show_existing_frame = true;
+  gold.frame_to_show = kFrameToShow;
+  gold.frame_presentation_time = 38;
+
+  EXPECT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->frame_width_bits = kFrameWidthBits;
+  obu_sequence_header_->frame_height_bits = kFrameHeightBits;
+  obu_sequence_header_->max_frame_width = kWidth;
+  obu_sequence_header_->max_frame_height = kHeight;
+
+  obu_sequence_header_->decoder_model_info_present_flag = true;
+  obu_sequence_header_->decoder_model_info.frame_presentation_time_length = 20;
+
+  decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer();
+  decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true);
+
+  ASSERT_TRUE(ObuParseFrameParameters());
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterErrorResilientMode) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameIntraOnly);
+
+  gold.error_resilient_mode = true;
+  data.SetBit(4, static_cast<uint8_t>(gold.error_resilient_mode));
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterKeyFrame) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderKeyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterKeyFrameTemporalPointInfo) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderKeyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+
+  data.InsertLiteral(4, 20, 38);  // frame_presentation_time.
+  gold.frame_presentation_time = 38;
+
+  EXPECT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->frame_width_bits = kFrameWidthBits;
+  obu_sequence_header_->frame_height_bits = kFrameHeightBits;
+  obu_sequence_header_->max_frame_width = kWidth;
+  obu_sequence_header_->max_frame_height = kHeight;
+
+  obu_sequence_header_->decoder_model_info_present_flag = true;
+  obu_sequence_header_->decoder_model_info.frame_presentation_time_length = 20;
+
+  ASSERT_TRUE(ObuParseFrameParameters());
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterKeyFrameOverrideSize) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderKeyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+
+  OverrideFrameSize(&data, &gold, 5, 6);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+
+  OverrideRenderSize(&data, &gold, 23);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterKeyFrameSuperRes) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderKeyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+  gold.use_superres = true;
+  gold.superres_scale_denominator = 15;
+  gold.width = kWidth * 8 / 15;
+  gold.columns4x4 = 58;
+
+  data.SetBit(6, static_cast<int>(gold.use_superres));
+  data.SetLiteral(7, 3, gold.superres_scale_denominator - 9);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 0, 0, true));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterKeyFrameAllowScreenContentTools) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderKeyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameKey);
+
+  data.InsertBit(5, 1);  // allow_screen_content_tools.
+  data.InsertBit(8, 1);  // allow_intrabc.
+  gold.allow_screen_content_tools = true;
+  gold.allow_intrabc = true;
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2));
+  VerifyFrameParameters(gold);
+
+  data.InsertBit(6, 1);  // force_integer_mv.
+  gold.force_integer_mv = 1;
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2, 2));
+  VerifyFrameParameters(gold);
+
+  data.SetBit(6, 0);  // force_integer_mv.
+
+  // Gold need not be updated, because force_integer_mv is always 1 for
+  // keyframes.
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2, 2));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterIntraOnlyFrame) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameIntraOnly);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterIntraOnlyFrameOverrideSize) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameIntraOnly);
+
+  OverrideFrameSize(&data, &gold, 6, 15);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+
+  OverrideRenderSize(&data, &gold, 32);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+// An INTRA_ONLY_FRAME cannot set refresh_frame_flags to 0xff.
+TEST_F(ObuParserTest, FrameParameterIntraOnlyFrameRefreshAllFrames) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame);
+  data.SetLiteral(7, 8, 0xFF);  // refresh_frame_flags.
+
+  ASSERT_FALSE(ParseFrameParameters(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, FrameParameterInterFrame) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderInterFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameInter);
+  ObuFrameHeader reference_frame_header;
+  reference_frame_header.width = kWidth;
+  reference_frame_header.height = kHeight;
+  reference_frame_header.render_width = kWidth;
+  reference_frame_header.render_height = kHeight;
+  reference_frame_header.upscaled_width = kWidth;
+  reference_frame_header.rows4x4 = kRows4x4;
+  reference_frame_header.columns4x4 = kColumns4x4;
+  reference_frame_header.refresh_frame_flags = 0;
+  for (auto& reference_frame : decoder_state_.reference_frame) {
+    reference_frame = buffer_pool_->GetFreeBuffer();
+    EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header));
+  }
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+TEST_F(ObuParserTest, FrameParameterInterFrameOverrideSize) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderInterFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameInter);
+  ObuFrameHeader reference_frame_header;
+  reference_frame_header.width = kWidth;
+  reference_frame_header.height = kHeight;
+  reference_frame_header.render_width = kWidth;
+  reference_frame_header.render_height = kHeight;
+  reference_frame_header.upscaled_width = kWidth;
+  reference_frame_header.rows4x4 = kRows4x4;
+  reference_frame_header.columns4x4 = kColumns4x4;
+  reference_frame_header.refresh_frame_flags = 0;
+  for (auto& reference_frame : decoder_state_.reference_frame) {
+    reference_frame = buffer_pool_->GetFreeBuffer();
+    EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header));
+  }
+
+  data.InsertLiteral(39, kNumInterReferenceFrameTypes, 0);  // found_ref.
+  OverrideFrameSize(&data, &gold, 6, 46);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+
+  OverrideRenderSize(&data, &gold, 63);
+
+  ASSERT_TRUE(ParseFrameParameters(data.GenerateData()));
+  VerifyFrameParameters(gold);
+}
+
+// This test verifies we check the following requirement at the end of Section
+// 6.8.4:
+//   If FrameIsIntra is equal to 0 (indicating that this frame may use inter
+//   prediction), the requirements described in the frame size with refs
+//   semantics of section 6.8.6 must also be satisfied.
+TEST_F(ObuParserTest, FrameParameterInterFrameInvalidSize) {
+  BytesAndBits data;
+  data.AppendBytes(kDefaultFrameHeaderInterFrame);
+  ObuFrameHeader gold;
+  DefaultFrameHeader(&gold, kFrameInter);
+  ObuFrameHeader reference_frame_header;
+  reference_frame_header.width = kWidth;
+  reference_frame_header.height = 2 * kHeight + 8;
+  reference_frame_header.render_width = kWidth;
+  reference_frame_header.render_height = 2 * kHeight + 8;
+  reference_frame_header.upscaled_width = kWidth;
+  reference_frame_header.rows4x4 = 2 * kRows4x4 + 2;
+  reference_frame_header.columns4x4 = kColumns4x4;
+  reference_frame_header.refresh_frame_flags = 0;
+  for (auto& reference_frame : decoder_state_.reference_frame) {
+    reference_frame = buffer_pool_->GetFreeBuffer();
+    EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header));
+  }
+
+  EXPECT_FALSE(ParseFrameParameters(data.GenerateData()));
+}
+
+// Tests the ObuParser::SetFrameReferences() method.
+//
+// This method uses the following data members as input:
+//   decoder_state_.reference_order_hint
+//   sequence_header_.enable_order_hint
+//   sequence_header_.order_hint_bits
+//   frame_header_.order_hint
+// So we need to set up these data members before calling
+// ObuParser::SetFrameReferences().
+//
+// The output is in frame_header_.reference_frame_index.
+TEST_F(ObuParserTest, SetFrameReferences) {
+  // All reference frames are forward references (because 9 < 17).
+  for (int i = 0; i < kNumReferenceFrameTypes; ++i) {
+    decoder_state_.reference_order_hint[i] = 9;
+  }
+
+  ASSERT_TRUE(Init());
+  obu_sequence_header_->enable_order_hint = true;
+  obu_sequence_header_->order_hint_bits = 5;
+  obu_sequence_header_->order_hint_shift_bits =
+      Mod32(32 - obu_sequence_header_->order_hint_bits);
+  obu_frame_header_->order_hint = 17;
+
+  const int8_t last_frame_idx = 0;
+  const int8_t gold_frame_idx = 1;
+
+  // Since all reference frames are forward references, we set the remaining
+  // five references in reverse chronological order. So Last2, Last3, Backward,
+  // Alternate2, and Alternate are set to 7, 6, 5, 4, and 3, respectively.
+
+  EXPECT_TRUE(ObuSetFrameReferences(last_frame_idx, gold_frame_idx));
+
+  EXPECT_EQ(
+      obu_frame_header_
+          ->reference_frame_index[kReferenceFrameLast - kReferenceFrameLast],
+      0);
+  EXPECT_EQ(
+      obu_frame_header_
+          ->reference_frame_index[kReferenceFrameLast2 - kReferenceFrameLast],
+      7);
+  EXPECT_EQ(
+      obu_frame_header_
+          ->reference_frame_index[kReferenceFrameLast3 - kReferenceFrameLast],
+      6);
+  EXPECT_EQ(
+      obu_frame_header_
+          ->reference_frame_index[kReferenceFrameGolden - kReferenceFrameLast],
+      1);
+  EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameBackward -
+                                                     kReferenceFrameLast],
+            5);
+  EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameAlternate2 -
+                                                     kReferenceFrameLast],
+            4);
+  EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameAlternate -
+                                                     kReferenceFrameLast],
+            3);
+}
+
+TEST_F(ObuParserTest, LoopFilterParameters) {
+  LoopFilter gold;
+  memset(&gold, 0, sizeof(gold));
+
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone;
+  obu_frame_header_->coded_lossless = true;
+  gold.ref_deltas[kReferenceFrameIntra] = 1;
+  gold.ref_deltas[kReferenceFrameGolden] = -1;
+  gold.ref_deltas[kReferenceFrameAlternate] = -1;
+  gold.ref_deltas[kReferenceFrameAlternate2] = -1;
+  ASSERT_TRUE(ObuParseLoopFilterParameters());
+  VerifyLoopFilterParameters(gold);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone;
+  obu_frame_header_->allow_intrabc = true;
+  ASSERT_TRUE(ObuParseLoopFilterParameters());
+  VerifyLoopFilterParameters(gold);
+
+  gold.level[0] = 32;
+  gold.level[3] = 48;
+  gold.sharpness = 4;
+  data.Clear();
+  for (const auto& level : gold.level) {
+    data.AppendLiteral(6, level);
+  }
+  data.AppendLiteral(3, gold.sharpness);
+  data.AppendBit(0);  // delta_enabled.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone;
+  ASSERT_TRUE(ObuParseLoopFilterParameters());
+  VerifyLoopFilterParameters(gold);
+
+  gold.delta_enabled = true;
+  gold.delta_update = true;
+  gold.ref_deltas[0] = 20;
+  gold.mode_deltas[0] = -20;
+  data.SetBit(27, 1);  // delta_enabled.
+  data.AppendBit(1);   // delta_update.
+  for (int i = 0; i < kNumReferenceFrameTypes; ++i) {
+    if (i == 0) {
+      data.AppendBit(1);  // update_ref_delta.
+      data.AppendInverseSignedLiteral(6, gold.ref_deltas[0]);  // ref_delta.
+    } else {
+      data.AppendBit(0);  // update_ref_delta.
+    }
+  }
+  for (int i = 0; i < kLoopFilterMaxModeDeltas; ++i) {
+    if (i == 0) {
+      data.AppendBit(1);  // update_mode_delta.
+      data.AppendInverseSignedLiteral(6, gold.mode_deltas[0]);  // mode_delta.
+    } else {
+      data.AppendBit(0);  // update_mode_delta.
+    }
+  }
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone;
+  ASSERT_TRUE(ObuParseLoopFilterParameters());
+  VerifyLoopFilterParameters(gold);
+}
+
+TEST_F(ObuParserTest, QuantizerParameters) {
+  QuantizerParameters gold = {};
+  gold.base_index = 48;
+
+  BytesAndBits data;
+  data.AppendLiteral(8, gold.base_index);
+  data.AppendLiteral(3, 0);  // delta_coded.
+  data.AppendBit(0);         // use_matrix.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+}
+
+TEST_F(ObuParserTest, QuantizerParametersMonochrome) {
+  QuantizerParameters gold = {};
+  gold.base_index = 48;
+
+  BytesAndBits data;
+  data.AppendLiteral(8, gold.base_index);
+  data.AppendBit(0);  // delta_coded.
+  data.AppendBit(0);  // use_matrix.
+  // The quantizer parameters end here. Add a 1 bit. It should not be parsed.
+  data.AppendBit(1);  // Would be segmentation_enabled in a bitstream.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.is_monochrome = true;
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+}
+
+TEST_F(ObuParserTest, QuantizerParametersDeltaCoded) {
+  QuantizerParameters gold = {};
+  gold.base_index = 48;
+  gold.delta_dc[kPlaneY] = -30;
+
+  BytesAndBits data;
+  data.AppendLiteral(8, gold.base_index);
+  data.AppendBit(1);  // delta_coded.
+  data.AppendInverseSignedLiteral(6, gold.delta_dc[kPlaneY]);
+  data.AppendLiteral(2, 0);  // delta_coded u dc/ac.
+  data.AppendBit(0);         // use_matrix.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  gold.delta_dc[kPlaneU] = -40;
+  gold.delta_dc[kPlaneV] = gold.delta_dc[kPlaneU];
+  data.SetBit(16, 1);  // delta_coded.
+  data.InsertInverseSignedLiteral(17, 6, gold.delta_dc[kPlaneU]);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  gold.delta_ac[kPlaneU] = 50;
+  gold.delta_ac[kPlaneV] = gold.delta_ac[kPlaneU];
+  data.SetBit(24, 1);  // delta_coded.
+  data.InsertInverseSignedLiteral(25, 6, gold.delta_ac[kPlaneU]);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  gold.delta_dc[kPlaneV] = 60;
+  gold.delta_ac[kPlaneV] = 0;
+  data.InsertBit(16, 1);  // diff_uv_delta.
+  data.InsertBit(33, 1);  // delta_coded.
+  data.InsertInverseSignedLiteral(34, 6, gold.delta_dc[kPlaneV]);
+  data.InsertBit(41, 0);  // delta_coded.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.separate_uv_delta_q = true;
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  gold.delta_ac[kPlaneV] = -20;
+  data.SetBit(41, 1);  // delta_coded.
+  data.InsertInverseSignedLiteral(42, 6, gold.delta_ac[kPlaneV]);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.separate_uv_delta_q = true;
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+}
+
+TEST_F(ObuParserTest, QuantizerParametersUseQmatrix) {
+  QuantizerParameters gold = {};
+  gold.base_index = 48;
+  gold.use_matrix = true;
+  gold.matrix_level[kPlaneY] = 3;
+  gold.matrix_level[kPlaneU] = 6;
+  gold.matrix_level[kPlaneV] = gold.matrix_level[kPlaneU];
+
+  // Test three cases.
+  // 1. separate_uv_delta_q = false (which implies diff_uv_delta = false).
+  BytesAndBits data;
+  data.AppendLiteral(8, gold.base_index);
+  data.AppendLiteral(3, 0);  // delta_coded.
+  data.AppendBit(static_cast<uint8_t>(gold.use_matrix));
+  data.AppendLiteral(4, gold.matrix_level[kPlaneY]);
+  data.AppendLiteral(4, gold.matrix_level[kPlaneU]);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  // 2. separate_uv_delta_q = true and diff_uv_delta = false.
+  gold.matrix_level[kPlaneV] = 5;
+  data.InsertBit(9, 0);  // diff_uv_delta.
+  data.AppendLiteral(4, gold.matrix_level[kPlaneV]);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.separate_uv_delta_q = true;
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+
+  // 3. separate_uv_delta_q = true and diff_uv_delta = true.
+  data.SetBit(9, 1);             // diff_uv_delta.
+  data.InsertLiteral(12, 2, 0);  // delta_coded.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.separate_uv_delta_q = true;
+  ASSERT_TRUE(ObuParseQuantizerParameters());
+  VerifyQuantizerParameters(gold);
+}
+
+TEST_F(ObuParserTest, SegmentationParameters) {
+  const int kPrimaryReferenceNotNone = 1;
+  const int kPrevFrameIndexNotNone = 2;
+
+  // Set up decoder_state_ with a previous frame containing saved segmentation
+  // parameters.
+  decoder_state_.reference_frame[kPrevFrameIndexNotNone] =
+      buffer_pool_->GetFreeBuffer();
+  ASSERT_NE(decoder_state_.reference_frame[kPrevFrameIndexNotNone], nullptr);
+  Segmentation prev_segmentation = {};
+  prev_segmentation.feature_enabled[2][0] = true;
+  prev_segmentation.feature_enabled[5][0] = true;
+  prev_segmentation.last_active_segment_id = 5;
+  decoder_state_.reference_frame[kPrevFrameIndexNotNone]
+      ->SetSegmentationParameters(prev_segmentation);
+
+  Segmentation gold;
+  memset(&gold, 0, sizeof(gold));
+
+  BytesAndBits data;
+  data.AppendBit(0);  // segmentation_enabled.
+
+  // Since segmentation_enabled is false, we expect the parameters to be all
+  // zero/false.
+  ASSERT_TRUE(ParseSegmentationParameters(
+      data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone));
+  VerifySegmentationParameters(gold);
+
+  gold.enabled = true;
+  gold.update_map = true;
+  gold.temporal_update = true;
+  data.SetBit(0, static_cast<uint8_t>(gold.enabled));
+  data.AppendBit(static_cast<uint8_t>(gold.update_map));
+  data.AppendBit(static_cast<uint8_t>(gold.temporal_update));
+  data.AppendBit(static_cast<uint8_t>(gold.update_data));
+
+  // Since update_data is false, we expect the parameters to be loaded from the
+  // previous frame in |decoder_state_|. So change |gold| accordingly.
+  gold.feature_enabled[2][0] = true;
+  gold.feature_enabled[5][0] = true;
+  gold.last_active_segment_id = 5;
+
+  ASSERT_TRUE(ParseSegmentationParameters(
+      data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone));
+  VerifySegmentationParameters(gold);
+
+  OverrideSegmentation(&data, &gold, 3);
+
+  ASSERT_TRUE(ParseSegmentationParameters(
+      data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone));
+  VerifySegmentationParameters(gold);
+
+  // If primary_ref_frame is kPrimaryReferenceNone, these three fields are
+  // implied.
+  data.RemoveBit(1);  // segmentation_update_map.
+  data.RemoveBit(1);  // segmentation_temporal_update.
+  data.RemoveBit(1);  // segmentation_update_data.
+  gold.update_map = true;
+  gold.temporal_update = false;
+  gold.update_data = true;
+
+  // Since update_data is true, we expect the parameters to be read from
+  // |data|.
+  ASSERT_TRUE(ParseSegmentationParameters(data.GenerateData(),
+                                          kPrimaryReferenceNone, 0));
+  VerifySegmentationParameters(gold);
+}
+
+TEST_F(ObuParserTest, QuantizerIndexDeltaParameters) {
+  BytesAndBits data;
+  data.AppendBit(1);         // delta_q_present.
+  data.AppendLiteral(2, 2);  // delta_q_res.
+
+  Delta gold;
+  memset(&gold, 0, sizeof(gold));
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseQuantizerIndexDeltaParameters());
+  VerifyDeltaParameters(gold, obu_->frame_header().delta_q);
+
+  gold.present = true;
+  gold.scale = 2;
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->quantizer.base_index = 40;
+  ASSERT_TRUE(ObuParseQuantizerIndexDeltaParameters());
+  VerifyDeltaParameters(gold, obu_->frame_header().delta_q);
+}
+
+TEST_F(ObuParserTest, LoopFilterDeltaParameters) {
+  BytesAndBits data;
+  data.AppendBit(1);         // delta_lf_present.
+  data.AppendLiteral(2, 2);  // delta_lf_res.
+  data.AppendBit(1);         // delta_lf_multi.
+
+  Delta gold;
+  memset(&gold, 0, sizeof(gold));
+
+  // delta_q_present is false, so loop filter delta will not be read.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseLoopFilterDeltaParameters());
+  VerifyDeltaParameters(gold, obu_->frame_header().delta_lf);
+
+  // allow_intrabc is true, so loop filter delta will not be read.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->delta_q.present = true;
+  obu_frame_header_->allow_intrabc = true;
+  ASSERT_TRUE(ObuParseLoopFilterDeltaParameters());
+  VerifyDeltaParameters(gold, obu_->frame_header().delta_lf);
+
+  gold.present = true;
+  gold.scale = 2;
+  gold.multi = true;
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->delta_q.present = true;
+  ASSERT_TRUE(ObuParseLoopFilterDeltaParameters());
+  VerifyDeltaParameters(gold, obu_->frame_header().delta_lf);
+}
+
+TEST_F(ObuParserTest, ComputeSegmentLosslessAndQIndex) {
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+
+  // Segmentation is disabled. All quantizers are 0.
+  ObuComputeSegmentLosslessAndQIndex();
+  EXPECT_TRUE(obu_->frame_header().coded_lossless);
+  EXPECT_TRUE(obu_->frame_header().upscaled_lossless);
+  for (const auto& qindex : obu_->frame_header().segmentation.qindex) {
+    EXPECT_EQ(qindex, 0);
+  }
+
+  // Segmentation is enabled. All quantizers are zero.
+  obu_frame_header_->segmentation.enabled = true;
+  ObuComputeSegmentLosslessAndQIndex();
+  EXPECT_TRUE(obu_->frame_header().coded_lossless);
+  EXPECT_TRUE(obu_->frame_header().upscaled_lossless);
+  for (const auto& qindex : obu_->frame_header().segmentation.qindex) {
+    EXPECT_EQ(qindex, 0);
+  }
+
+  // Segmentation is enabled. All quantizers are zero. upscaled_width != width.
+  obu_frame_header_->segmentation.enabled = true;
+  obu_frame_header_->upscaled_width = 100;
+  ObuComputeSegmentLosslessAndQIndex();
+  EXPECT_TRUE(obu_->frame_header().coded_lossless);
+  EXPECT_FALSE(obu_->frame_header().upscaled_lossless);
+  for (const auto& qindex : obu_->frame_header().segmentation.qindex) {
+    EXPECT_EQ(qindex, 0);
+  }
+
+  // Segmentation in disabled. Some quantizer deltas are non zero.
+  obu_frame_header_->segmentation.enabled = false;
+  obu_frame_header_->quantizer.delta_dc[kPlaneY] = 40;
+  ObuComputeSegmentLosslessAndQIndex();
+  EXPECT_FALSE(obu_->frame_header().coded_lossless);
+  EXPECT_FALSE(obu_->frame_header().upscaled_lossless);
+  for (const auto& qindex : obu_->frame_header().segmentation.qindex) {
+    EXPECT_EQ(qindex, 0);
+  }
+
+  // Segmentation is disabled. Quantizer base index is non zero.
+  obu_frame_header_->segmentation.enabled = true;
+  obu_frame_header_->quantizer.delta_dc[kPlaneY] = 0;
+  obu_frame_header_->quantizer.base_index = 40;
+  ObuComputeSegmentLosslessAndQIndex();
+  EXPECT_FALSE(obu_->frame_header().coded_lossless);
+  EXPECT_FALSE(obu_->frame_header().upscaled_lossless);
+  for (const auto& qindex : obu_->frame_header().segmentation.qindex) {
+    EXPECT_EQ(qindex, 40);
+  }
+}
+
+TEST_F(ObuParserTest, CdefParameters) {
+  Cdef gold;
+  memset(&gold, 0, sizeof(gold));
+  const int coeff_shift = 2;  // bitdepth - 8.
+  gold.damping = 3 + coeff_shift;
+
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->color_config.bitdepth = 10;
+  ASSERT_TRUE(ObuParseCdefParameters());
+  // Cdef will be {0} except for damping because enable_cdef is false.
+  VerifyCdefParameters(gold);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->enable_cdef = true;
+  obu_sequence_header_->color_config.bitdepth = 10;
+  obu_frame_header_->coded_lossless = true;
+  ASSERT_TRUE(ObuParseCdefParameters());
+  // Cdef will be {0} except for damping because coded_lossless is true.
+  VerifyCdefParameters(gold);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->enable_cdef = true;
+  obu_sequence_header_->color_config.bitdepth = 10;
+  obu_frame_header_->allow_intrabc = true;
+  ASSERT_TRUE(ObuParseCdefParameters());
+  // Cdef will be {0} except for damping because allow_intrabc is true.
+  VerifyCdefParameters(gold);
+
+  gold.damping = 5;
+  gold.bits = 1;
+  data.Clear();
+  data.AppendLiteral(2, gold.damping - 3);  // cdef_damping_minus3.
+  gold.damping += coeff_shift;
+  data.AppendLiteral(2, gold.bits);  // cdef_bits.
+  for (int i = 0; i < 2; ++i) {
+    gold.y_primary_strength[i] = 10;
+    gold.y_secondary_strength[i] = (i == 0) ? 2 : 3;
+    gold.uv_primary_strength[i] = 12;
+    gold.uv_secondary_strength[i] = (i == 1) ? 2 : 3;
+    data.AppendLiteral(4, gold.y_primary_strength[i]);
+    data.AppendLiteral(2, gold.y_secondary_strength[i]);
+    data.AppendLiteral(4, gold.uv_primary_strength[i]);
+    data.AppendLiteral(2, gold.uv_secondary_strength[i]);
+    if (gold.y_secondary_strength[i] == 3) ++gold.y_secondary_strength[i];
+    if (gold.uv_secondary_strength[i] == 3) ++gold.uv_secondary_strength[i];
+    gold.y_primary_strength[i] <<= coeff_shift;
+    gold.uv_primary_strength[i] <<= coeff_shift;
+    gold.y_secondary_strength[i] <<= coeff_shift;
+    gold.uv_secondary_strength[i] <<= coeff_shift;
+  }
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_sequence_header_->enable_cdef = true;
+  obu_sequence_header_->color_config.bitdepth = 10;
+  ASSERT_TRUE(ObuParseCdefParameters());
+  VerifyCdefParameters(gold);
+}
+
+TEST_F(ObuParserTest, LoopRestorationParameters) {
+  for (bool use_128x128_superblock : testing::Bool()) {
+    SCOPED_TRACE("use_128x128_superblock: " +
+                 std::to_string(use_128x128_superblock));
+    LoopRestoration gold;
+    memset(&gold, 0, sizeof(gold));
+
+    BytesAndBits data;
+    data.AppendBit(0);  // dummy.
+
+    // enable_restoration is false. nothing will be read.
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_frame_header_->allow_intrabc = true;
+    obu_frame_header_->coded_lossless = true;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+
+    // allow_intrabc is true. nothing will be read.
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_frame_header_->allow_intrabc = true;
+    obu_sequence_header_->enable_restoration = true;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+
+    // coded_lossless is true. nothing will be read.
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_frame_header_->coded_lossless = true;
+    obu_sequence_header_->enable_restoration = true;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+
+    data.Clear();
+    for (int i = 0; i < kMaxPlanes; ++i) {
+      data.AppendLiteral(2, kLoopRestorationTypeNone);  // lr_type.
+    }
+
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_sequence_header_->enable_restoration = true;
+    obu_sequence_header_->use_128x128_superblock = use_128x128_superblock;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+
+    gold.type[0] = gold.type[1] = kLoopRestorationTypeWiener;
+    gold.unit_size_log2[0] = gold.unit_size_log2[1] = gold.unit_size_log2[2] =
+        use_128x128_superblock ? 8 : 7;
+    data.SetLiteral(0, 2, gold.type[0]);  // lr_type.
+    data.SetLiteral(2, 2, gold.type[0]);  // lr_type.
+    data.AppendBit(1);                    // lr_unit_shift.
+    if (!use_128x128_superblock) {
+      data.AppendBit(0);  // lr_unit_extra_shift.
+    }
+
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_sequence_header_->enable_restoration = true;
+    obu_sequence_header_->use_128x128_superblock = use_128x128_superblock;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+
+    if (!use_128x128_superblock) {
+      gold.unit_size_log2[0] = gold.unit_size_log2[1] = gold.unit_size_log2[2] =
+          8;
+      data.SetBit(7, 1);  // lr_unit_extra_shift.
+
+      ASSERT_TRUE(Init(data.GenerateData()));
+      obu_sequence_header_->enable_restoration = true;
+      obu_sequence_header_->use_128x128_superblock = use_128x128_superblock;
+      ASSERT_TRUE(ObuParseLoopRestorationParameters());
+      VerifyLoopRestorationParameters(gold);
+    }
+
+    gold.unit_size_log2[1] = gold.unit_size_log2[2] = 7;
+    data.AppendBit(1);  // lr_uv_shift.
+
+    ASSERT_TRUE(Init(data.GenerateData()));
+    obu_sequence_header_->enable_restoration = true;
+    obu_sequence_header_->use_128x128_superblock = use_128x128_superblock;
+    obu_sequence_header_->color_config.subsampling_x = 1;
+    obu_sequence_header_->color_config.subsampling_y = 1;
+    ASSERT_TRUE(ObuParseLoopRestorationParameters());
+    VerifyLoopRestorationParameters(gold);
+  }
+}
+
+TEST_F(ObuParserTest, TxModeSyntax) {
+  BytesAndBits data;
+  data.AppendBit(1);  // tx_mode_select.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseTxModeSyntax());
+  EXPECT_EQ(kTxModeSelect, obu_->frame_header().tx_mode);
+
+  data.SetBit(0, 0);  // tx_mode_select.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  ASSERT_TRUE(ObuParseTxModeSyntax());
+  EXPECT_EQ(kTxModeLargest, obu_->frame_header().tx_mode);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->coded_lossless = true;
+  ASSERT_TRUE(ObuParseTxModeSyntax());
+  EXPECT_EQ(kTxModeOnly4x4, obu_->frame_header().tx_mode);
+}
+
+TEST_F(ObuParserTest, FrameReferenceModeSyntax) {
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+
+  ASSERT_TRUE(ParseFrameReferenceModeSyntax(data.GenerateData(), kFrameKey));
+  EXPECT_FALSE(obu_->frame_header().reference_mode_select);
+
+  data.SetBit(0, 1);  // reference_mode_select.
+
+  ASSERT_TRUE(ParseFrameReferenceModeSyntax(data.GenerateData(), kFrameInter));
+  EXPECT_TRUE(obu_->frame_header().reference_mode_select);
+}
+
+TEST_F(ObuParserTest, SkipModeParameters) {
+  BytesAndBits data;
+  data.AppendBit(1);  // skip_mode_present.
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameKey;
+  ASSERT_FALSE(ObuIsSkipModeAllowed());
+  ASSERT_TRUE(ObuParseSkipModeParameters());
+  EXPECT_FALSE(obu_->frame_header().skip_mode_present);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->reference_mode_select = true;
+  ASSERT_FALSE(ObuIsSkipModeAllowed());
+  ASSERT_TRUE(ObuParseSkipModeParameters());
+  EXPECT_FALSE(obu_->frame_header().skip_mode_present);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->reference_mode_select = true;
+  obu_sequence_header_->enable_order_hint = true;
+  obu_sequence_header_->order_hint_bits = 7;
+  obu_sequence_header_->order_hint_shift_bits =
+      Mod32(32 - obu_sequence_header_->order_hint_bits);
+  ASSERT_FALSE(ObuIsSkipModeAllowed());
+  ASSERT_TRUE(ObuParseSkipModeParameters());
+  EXPECT_FALSE(obu_->frame_header().skip_mode_present);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->reference_mode_select = true;
+  obu_frame_header_->order_hint = 1;
+  decoder_state_.order_hint = 1;
+  obu_sequence_header_->enable_order_hint = true;
+  obu_sequence_header_->order_hint_bits = 7;
+  obu_sequence_header_->order_hint_shift_bits =
+      Mod32(32 - obu_sequence_header_->order_hint_bits);
+  ASSERT_FALSE(ObuIsSkipModeAllowed());
+  ASSERT_TRUE(ObuParseSkipModeParameters());
+  EXPECT_FALSE(obu_->frame_header().skip_mode_present);
+
+  ASSERT_TRUE(Init(data.GenerateData()));
+  for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) {
+    obu_frame_header_->reference_frame_index[i] = i;
+    decoder_state_.reference_order_hint[i] = i;
+  }
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->reference_mode_select = true;
+  obu_frame_header_->order_hint = 1;
+  decoder_state_.order_hint = 1;
+  obu_sequence_header_->enable_order_hint = true;
+  obu_sequence_header_->order_hint_bits = 7;
+  obu_sequence_header_->order_hint_shift_bits =
+      Mod32(32 - obu_sequence_header_->order_hint_bits);
+  ASSERT_TRUE(ObuIsSkipModeAllowed());
+  ASSERT_TRUE(ObuParseSkipModeParameters());
+  EXPECT_TRUE(obu_->frame_header().skip_mode_present);
+}
+
+TEST_F(ObuParserTest, AllowWarpedMotion) {
+  BytesAndBits data;
+  data.AppendBit(0xff);  // dummy.
+
+  // IsIntraFrame is true, so nothing will be read.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameKey;
+  obu_frame_header_->error_resilient_mode = false;
+  obu_sequence_header_->enable_warped_motion = true;
+  ASSERT_TRUE(ObuReadAllowWarpedMotion());
+  EXPECT_FALSE(obu_->frame_header().allow_warped_motion);
+
+  // error_resilient_mode is true, so nothing will be read.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->error_resilient_mode = true;
+  obu_sequence_header_->enable_warped_motion = true;
+  ASSERT_TRUE(ObuReadAllowWarpedMotion());
+  EXPECT_FALSE(obu_->frame_header().allow_warped_motion);
+
+  // enable_warped_motion is false, so nothing will be read.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->error_resilient_mode = false;
+  obu_sequence_header_->enable_warped_motion = false;
+  ASSERT_TRUE(ObuReadAllowWarpedMotion());
+  EXPECT_FALSE(obu_->frame_header().allow_warped_motion);
+
+  // allow_warped_motion will be read and equal to true.
+  ASSERT_TRUE(Init(data.GenerateData()));
+  obu_frame_header_->frame_type = kFrameInter;
+  obu_frame_header_->error_resilient_mode = false;
+  obu_sequence_header_->enable_warped_motion = true;
+  ASSERT_TRUE(ObuReadAllowWarpedMotion());
+  EXPECT_TRUE(obu_->frame_header().allow_warped_motion);
+}
+
+TEST_F(ObuParserTest, GlobalMotionParameters) {
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+  std::array<GlobalMotion, kNumReferenceFrameTypes> gold;
+  for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) {
+    gold[i].type = kGlobalMotionTransformationTypeIdentity;
+    for (int j = 0; j < 6; ++j) {
+      gold[i].params[j] = (j % 3 == 2) ? 1 << kWarpedModelPrecisionBits : 0;
+    }
+  }
+
+  ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameKey));
+  VerifyGlobalMotionParameters(gold);
+
+  data.Clear();
+  for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) {
+    // is_global=1; is_rot_zoom=1; parameter_values;
+    data.AppendBytes(kDefaultGlobalMotionParametersRotZoom);
+
+    // Magic numbers based on kDefaultGlobalMotionParametersRotZoom.
+    gold[i].type = kGlobalMotionTransformationTypeRotZoom;
+    gold[i].params[0] = -73728;
+    gold[i].params[1] = -23552;
+    gold[i].params[2] = 65952;
+    gold[i].params[3] = -62;
+    gold[i].params[4] = 62;
+    gold[i].params[5] = 65952;
+  }
+
+  ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameInter));
+  VerifyGlobalMotionParameters(gold);
+
+  data.Clear();
+  for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) {
+    // This bit is not part of the hex string because it would make the whole
+    // string not align to 8 bits. Appending this separately so that we can keep
+    // the rest of them a magic hex string.
+    data.AppendBit(1);  // is_global.
+    // is_rot_zoom=0; is_translation=0; parameter_values;
+    data.AppendBytes(kDefaultGlobalMotionParametersAffine);
+
+    // Magic numbers based on kDefaultGlobalMotionParametersAffine.
+    gold[i].type = kGlobalMotionTransformationTypeAffine;
+    gold[i].params[4] = -62;
+  }
+
+  ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameInter));
+  VerifyGlobalMotionParameters(gold);
+}
+
+TEST_F(ObuParserTest, FilmGrainParameters) {
+  BytesAndBits data;
+  data.AppendBit(0);  // dummy.
+
+  // Test film grain not present.
+  FilmGrainParams gold = {};
+  ObuSequenceHeader sequence_header = {};
+  sequence_header.film_grain_params_present = false;
+  ObuFrameHeader frame_header = {};
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  VerifyFilmGrainParameters(gold);
+
+  // Test if show_frame = false and showable_frame = false.
+  data.Clear();
+  gold = {};
+  sequence_header.film_grain_params_present = true;
+  frame_header.show_frame = false;
+  frame_header.showable_frame = false;
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  VerifyFilmGrainParameters(gold);
+
+  // Test if apply_grain = false.
+  data.Clear();
+  gold = {};
+  sequence_header.film_grain_params_present = true;
+  frame_header.show_frame = true;
+  frame_header.showable_frame = true;
+  data.AppendBit(0);
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  VerifyFilmGrainParameters(gold);
+
+  // Test if update_grain = false.
+  data.Clear();
+  gold = {};
+  sequence_header.film_grain_params_present = true;
+  frame_header.show_frame = true;
+  frame_header.showable_frame = true;
+  frame_header.frame_type = kFrameInter;
+  for (auto& index : frame_header.reference_frame_index) {
+    index = 1;
+  }
+  data.AppendBit(1);
+  gold.apply_grain = true;
+  data.AppendLiteral(16, 8);
+  gold.grain_seed = 8;
+  data.AppendBit(0);
+  gold.update_grain = false;
+  data.AppendLiteral(3, 1);
+  gold.reference_index = 1;
+  // Set up decoder_state_ with a previous frame containing saved film grain
+  // parameters.
+  decoder_state_.reference_frame[1] = buffer_pool_->GetFreeBuffer();
+  EXPECT_NE(decoder_state_.reference_frame[1], nullptr);
+  FilmGrainParams prev_grain_params = {};
+  prev_grain_params.apply_grain = true;
+  prev_grain_params.grain_seed = 11;
+  prev_grain_params.update_grain = true;
+  decoder_state_.reference_frame[1]->set_film_grain_params(prev_grain_params);
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  VerifyFilmGrainParameters(gold);
+
+  // Test if update_grain = true, is_monochrome = true;
+  data.Clear();
+  gold = {};
+  frame_header.frame_type = kFrameKey;
+  for (auto& index : frame_header.reference_frame_index) {
+    index = 0;
+  }
+  data.AppendBit(1);
+  gold.apply_grain = true;
+  data.AppendLiteral(16, 8);
+  gold.grain_seed = 8;
+  gold.update_grain = true;
+  data.AppendLiteral(4, 10);
+  gold.num_y_points = 10;
+  for (int i = 0; i < gold.num_y_points; ++i) {
+    data.AppendLiteral(8, 2 * i);
+    gold.point_y_value[i] = 2 * i;
+    data.AppendLiteral(8, i);
+    gold.point_y_scaling[i] = i;
+  }
+  sequence_header.color_config.is_monochrome = true;
+  gold.chroma_scaling_from_luma = false;
+  gold.num_u_points = 0;
+  gold.num_v_points = 0;
+  data.AppendLiteral(2, 3);
+  gold.chroma_scaling = 11;
+  data.AppendLiteral(2, 1);
+  gold.auto_regression_coeff_lag = 1;
+  const int num_pos_luma =
+      2 * gold.auto_regression_coeff_lag * (gold.auto_regression_coeff_lag + 1);
+  for (int i = 0; i < num_pos_luma; ++i) {
+    data.AppendLiteral(8, i + 128);
+    gold.auto_regression_coeff_y[i] = i;
+  }
+  data.AppendLiteral(2, 0);
+  gold.auto_regression_shift = 6;
+  data.AppendLiteral(2, 1);
+  gold.grain_scale_shift = 1;
+  data.AppendBit(1);
+  gold.overlap_flag = true;
+  data.AppendBit(0);
+  gold.clip_to_restricted_range = false;
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  ASSERT_TRUE(
+      obu_->frame_header().frame_type == kFrameInter ||
+      obu_->frame_header().film_grain_params.update_grain);  // a implies b.
+  VerifyFilmGrainParameters(gold);
+
+  // Test if update_grain = true, is_monochrome = false;
+  data.Clear();
+  gold = {};
+  frame_header.frame_type = kFrameKey;
+  data.AppendBit(1);
+  gold.apply_grain = true;
+  data.AppendLiteral(16, 8);
+  gold.grain_seed = 8;
+  gold.update_grain = true;
+  data.AppendLiteral(4, 10);
+  gold.num_y_points = 10;
+  for (int i = 0; i < gold.num_y_points; ++i) {
+    data.AppendLiteral(8, 2 * i);
+    gold.point_y_value[i] = 2 * i;
+    data.AppendLiteral(8, i);
+    gold.point_y_scaling[i] = i;
+  }
+  sequence_header.color_config.is_monochrome = false;
+  data.AppendBit(0);
+  gold.chroma_scaling_from_luma = false;
+  data.AppendLiteral(4, 5);
+  gold.num_u_points = 5;
+  for (int i = 0; i < gold.num_u_points; ++i) {
+    data.AppendLiteral(8, 2 * i + 1);
+    gold.point_u_value[i] = 2 * i + 1;
+    data.AppendLiteral(8, i);
+    gold.point_u_scaling[i] = i;
+  }
+  data.AppendLiteral(4, 3);
+  gold.num_v_points = 3;
+  for (int i = 0; i < gold.num_v_points; ++i) {
+    data.AppendLiteral(8, i);
+    gold.point_v_value[i] = i;
+    data.AppendLiteral(8, i + 1);
+    gold.point_v_scaling[i] = i + 1;
+  }
+  data.AppendLiteral(2, 3);
+  gold.chroma_scaling = 11;
+  data.AppendLiteral(2, 1);
+  gold.auto_regression_coeff_lag = 1;
+  const int num_pos_luma2 =
+      2 * gold.auto_regression_coeff_lag * (gold.auto_regression_coeff_lag + 1);
+  for (int i = 0; i < num_pos_luma2; ++i) {
+    data.AppendLiteral(8, i + 128);
+    gold.auto_regression_coeff_y[i] = i;
+  }
+  for (int i = 0; i < num_pos_luma2 + 1; ++i) {
+    data.AppendLiteral(8, i);
+    gold.auto_regression_coeff_u[i] = i - 128;
+  }
+  for (int i = 0; i < num_pos_luma2 + 1; ++i) {
+    data.AppendLiteral(8, i);
+    gold.auto_regression_coeff_v[i] = i - 128;
+  }
+  data.AppendLiteral(2, 0);
+  gold.auto_regression_shift = 6;
+  data.AppendLiteral(2, 1);
+  gold.grain_scale_shift = 1;
+  data.AppendLiteral(8, 2);
+  gold.u_multiplier = -126;
+  data.AppendLiteral(8, 1);
+  gold.u_luma_multiplier = -127;
+  data.AppendLiteral(9, 3);
+  gold.u_offset = -253;
+  data.AppendLiteral(8, 3);
+  gold.v_multiplier = -125;
+  data.AppendLiteral(8, 2);
+  gold.v_luma_multiplier = -126;
+  data.AppendLiteral(9, 1);
+  gold.v_offset = -255;
+  data.AppendBit(1);
+  gold.overlap_flag = true;
+  data.AppendBit(0);
+  gold.clip_to_restricted_range = false;
+  ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header,
+                                       frame_header));
+  ASSERT_TRUE(
+      obu_->frame_header().frame_type == kFrameInter ||
+      obu_->frame_header().film_grain_params.update_grain);  // a implies b.
+  VerifyFilmGrainParameters(gold);
+}
+
+TEST_F(ObuParserTest, TileInfoSyntax) {
+  BytesAndBits data;
+  TileInfo gold;
+  memset(&gold, 0, sizeof(gold));
+
+  gold.uniform_spacing = true;
+  gold.tile_columns_log2 = 1;
+  gold.tile_columns = 2;
+  gold.tile_rows_log2 = 1;
+  gold.tile_rows = 2;
+  gold.tile_count = 4;
+  gold.tile_column_start[1] = 64;
+  gold.tile_column_start[2] = 88;
+  gold.tile_row_start[1] = 64;
+  gold.tile_row_start[2] = 72;
+  gold.context_update_id = 3;
+  gold.tile_size_bytes = 4;
+  data.AppendBit(static_cast<uint8_t>(gold.uniform_spacing));
+  data.AppendBit(1);  // increment_tile_cols_log2.
+  data.AppendBit(0);  // increment_tile_cols_log2.
+  data.AppendBit(1);  // increment_tile_rows_log2.
+  data.AppendBit(0);  // increment_tile_rows_log2.
+  data.AppendBit(1);  // context update id, columns_log2+rows_log2 bits
+  data.AppendBit(1);
+  data.AppendLiteral(2, gold.tile_size_bytes - 1);
+
+  ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true));
+  VerifyTileInfoParameters(gold);
+
+  gold.uniform_spacing = false;
+  gold.tile_column_width_in_superblocks[0] = 2;
+  gold.tile_column_width_in_superblocks[1] = 1;
+  gold.tile_row_height_in_superblocks[0] = 2;
+  gold.tile_row_height_in_superblocks[1] = 1;
+
+  data.SetBit(0, static_cast<uint8_t>(gold.uniform_spacing));
+  // The next 4 bits remain the same except now they represent f(w - 1) and
+  // extra_bit in DecodeUniform. All the subsequent bits are unchanged the
+  // represent the same thing as above.
+
+  ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true));
+  VerifyTileInfoParameters(gold);
+
+  // No tiles.
+  memset(&gold, 0, sizeof(gold));
+  gold.uniform_spacing = true;
+  gold.tile_columns = 1;
+  gold.tile_rows = 1;
+  gold.tile_count = 1;
+  gold.tile_column_start[1] = 88;
+  gold.tile_row_start[1] = 72;
+  data.Clear();
+  data.AppendBit(static_cast<uint8_t>(gold.uniform_spacing));
+  data.AppendBit(0);  // tile_cols_log2.
+  data.AppendBit(0);  // tile_rows_log2.
+
+  ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true));
+  VerifyTileInfoParameters(gold);
+
+  // 64x64 superblocks. No tiles.
+  gold.tile_column_start[1] = 640;
+  gold.tile_row_start[1] = 360;
+
+  ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 640, 360, false));
+  VerifyTileInfoParameters(gold);
+}
+
+TEST_F(ObuParserTest, MetadataUnknownType) {
+  BytesAndBits data;
+  // The metadata_type 10 is a user private value (6-31).
+  data.AppendLiteral(8, 10);  // metadata_type.
+  // The Note in Section 5.8.1 says "Decoders should ignore the entire OBU if
+  // they do not understand the metadata_type."
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, MetadataHdrCll) {
+  BytesAndBits data;
+  ObuMetadataHdrCll gold;
+  gold.max_cll = 25;
+  gold.max_fall = 100;
+
+  data.AppendLiteral(8, kMetadataTypeHdrContentLightLevel);
+  data.AppendLiteral(16, gold.max_cll);
+  data.AppendLiteral(16, gold.max_fall);
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+  VerifyMetadataHdrCll(gold);
+}
+
+TEST_F(ObuParserTest, MetadataHdrMdcv) {
+  BytesAndBits data;
+  ObuMetadataHdrMdcv gold;
+  for (int i = 0; i < 3; ++i) {
+    gold.primary_chromaticity_x[i] = 0;
+    gold.primary_chromaticity_y[i] = 0;
+  }
+  gold.white_point_chromaticity_x = 250;
+  gold.white_point_chromaticity_y = 2500;
+  gold.luminance_max = 6000;
+  gold.luminance_min = 3000;
+
+  data.AppendLiteral(8, kMetadataTypeHdrMasteringDisplayColorVolume);
+  for (int i = 0; i < 3; ++i) {
+    data.AppendLiteral(16, gold.primary_chromaticity_x[i]);
+    data.AppendLiteral(16, gold.primary_chromaticity_y[i]);
+  }
+  data.AppendLiteral(16, gold.white_point_chromaticity_x);
+  data.AppendLiteral(16, gold.white_point_chromaticity_y);
+  data.AppendLiteral(32, gold.luminance_max);
+  data.AppendLiteral(32, gold.luminance_min);
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+  VerifyMetadataHdrMdcv(gold);
+}
+
+TEST_F(ObuParserTest, MetadataScalability) {
+  BytesAndBits data;
+
+  data.AppendLiteral(8, kMetadataTypeScalability);
+  data.AppendLiteral(8, 0);  // scalability_mode_idc
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, MetadataItutT35) {
+  BytesAndBits data;
+  ObuMetadataItutT35 gold;
+  gold.country_code = 0xA6;  // 1 0 1 0 0 1 1 0 Switzerland
+  DynamicBuffer<uint8_t> payload_bytes;
+  ASSERT_TRUE(payload_bytes.Resize(10));
+  gold.payload_bytes = payload_bytes.get();
+  for (int i = 0; i < 10; ++i) {
+    gold.payload_bytes[i] = 9 - i;
+  }
+  gold.payload_size = 10;
+
+  data.AppendLiteral(8, kMetadataTypeItutT35);
+  data.AppendLiteral(8, gold.country_code);
+  for (int i = 0; i < 10; ++i) {
+    data.AppendLiteral(8, 9 - i);
+  }
+  // For the kMetadataTypeItutT35 metadata type, we must include the trailing
+  // bit so that the end of the itu_t_t35_payload_bytes can be identified.
+  data.AppendLiteral(8, 0x80);
+  data.AppendLiteral(8, 0x00);
+  data.AppendLiteral(8, 0x00);
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+  VerifyMetadataItutT35(gold);
+
+  gold.country_code = 0xFF;
+  gold.country_code_extension_byte = 10;
+
+  data.SetLiteral(8, 8, gold.country_code);
+  data.InsertLiteral(16, 8, gold.country_code_extension_byte);
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+  VerifyMetadataItutT35(gold);
+}
+
+TEST_F(ObuParserTest, MetadataTimecode) {
+  BytesAndBits data;
+
+  data.AppendLiteral(8, kMetadataTypeTimecode);
+  data.AppendLiteral(5, 0);   // counting_type
+  data.AppendBit(1);          // full_timestamp_flag
+  data.AppendBit(0);          // discontinuity_flag
+  data.AppendBit(0);          // cnt_dropped_flag
+  data.AppendLiteral(9, 8);   // n_frames
+  data.AppendLiteral(6, 59);  // seconds_value
+  data.AppendLiteral(6, 59);  // minutes_value
+  data.AppendLiteral(5, 23);  // hours_value
+  data.AppendLiteral(5, 0);   // time_offset_length
+
+  ASSERT_TRUE(ParseMetadata(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, MetadataTimecodeInvalidSecondsValue) {
+  BytesAndBits data;
+
+  data.AppendLiteral(8, kMetadataTypeTimecode);
+  data.AppendLiteral(5, 0);   // counting_type
+  data.AppendBit(1);          // full_timestamp_flag
+  data.AppendBit(0);          // discontinuity_flag
+  data.AppendBit(0);          // cnt_dropped_flag
+  data.AppendLiteral(9, 8);   // n_frames
+  data.AppendLiteral(6, 60);  // seconds_value
+  data.AppendLiteral(6, 59);  // minutes_value
+  data.AppendLiteral(5, 23);  // hours_value
+  data.AppendLiteral(5, 0);   // time_offset_length
+
+  EXPECT_FALSE(ParseMetadata(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, MetadataTimecodeInvalidMinutesValue) {
+  BytesAndBits data;
+
+  data.AppendLiteral(8, kMetadataTypeTimecode);
+  data.AppendLiteral(5, 0);   // counting_type
+  data.AppendBit(1);          // full_timestamp_flag
+  data.AppendBit(0);          // discontinuity_flag
+  data.AppendBit(0);          // cnt_dropped_flag
+  data.AppendLiteral(9, 8);   // n_frames
+  data.AppendLiteral(6, 59);  // seconds_value
+  data.AppendLiteral(6, 60);  // minutes_value
+  data.AppendLiteral(5, 23);  // hours_value
+  data.AppendLiteral(5, 0);   // time_offset_length
+
+  EXPECT_FALSE(ParseMetadata(data.GenerateData()));
+}
+
+TEST_F(ObuParserTest, MetadataTimecodeInvalidHoursValue) {
+  BytesAndBits data;
+
+  data.AppendLiteral(8, kMetadataTypeTimecode);
+  data.AppendLiteral(5, 0);   // counting_type
+  data.AppendBit(1);          // full_timestamp_flag
+  data.AppendBit(0);          // discontinuity_flag
+  data.AppendBit(0);          // cnt_dropped_flag
+  data.AppendLiteral(9, 8);   // n_frames
+  data.AppendLiteral(6, 59);  // seconds_value
+  data.AppendLiteral(6, 59);  // minutes_value
+  data.AppendLiteral(5, 24);  // hours_value
+  data.AppendLiteral(5, 0);   // time_offset_length
+
+  EXPECT_FALSE(ParseMetadata(data.GenerateData()));
+}
+
+}  // namespace libgav1
diff --git a/src/post_filter_test.cc b/src/post_filter_test.cc
new file mode 100644
index 0000000..034d31f
--- /dev/null
+++ b/src/post_filter_test.cc
@@ -0,0 +1,1080 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/post_filter.h"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/cdef.h"
+#include "src/dsp/dsp.h"
+#include "src/dsp/super_res.h"
+#include "src/frame_scratch_buffer.h"
+#include "src/obu_parser.h"
+#include "src/threading_strategy.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/memory.h"
+#include "src/utils/types.h"
+#include "src/yuv_buffer.h"
+#include "tests/block_utils.h"
+#include "tests/third_party/libvpx/acm_random.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr char kCdef[] = "Cdef";
+constexpr char kApplyCdefName[] = "ApplyCdef";
+constexpr int kMaxBlockWidth4x4 = 32;
+constexpr int kMaxBlockHeight4x4 = 32;
+constexpr int kMaxTestFrameSize = 1920 * 1080;
+
+int GetIdFromInputParam(int subsampling_x, int subsampling_y, int height) {
+  int id = subsampling_x * 8 + subsampling_y * 4;
+  if (height == 288) {
+    id += 0;
+  } else if (height == 480) {
+    id += 1;
+  } else if (height == 1080) {
+    id += 2;
+  } else {
+    id += 3;
+  }
+  return id;
+}
+
+const char* GetSuperResDigest8bpp(int id, int plane) {
+  static const char* const kDigestSuperRes[][kMaxPlanes] = {
+      {
+          // all input is 0.
+          "ff5f7a63d3b1f9176e216eb01a0387ad",  // kPlaneY.
+          "38b6551d7ac3e86c8af407d5a1aa36dc",  // kPlaneU.
+          "38b6551d7ac3e86c8af407d5a1aa36dc",  // kPlaneV.
+      },
+      {
+          // all input is 1.
+          "819f21dcce0e779180bbd613a9e3543c",  // kPlaneY.
+          "e784bfa8f517d83b014c3dcd45b780a5",  // kPlaneU.
+          "e784bfa8f517d83b014c3dcd45b780a5",  // kPlaneV.
+      },
+      {
+          // all input is 128.
+          "2d6ea5b39f9168d56c2e2b8846d208ec",  // kPlaneY.
+          "8030b6e70f1544efbc37b902d3f88bd3",  // kPlaneU.
+          "8030b6e70f1544efbc37b902d3f88bd3",  // kPlaneV.
+      },
+      {
+          // all input is 255.
+          "5c0b4bc50e0980dc6ba7c042d3b50a5e",  // kPlaneY.
+          "3c566ef847c45be09ddac297123a3bad",  // kPlaneU.
+          "3c566ef847c45be09ddac297123a3bad",  // kPlaneV.
+      },
+      {
+          // random input.
+          "50514467dd6a5c3a8268eddaa542c41f",  // kPlaneY.
+          "3ce720c2b5b44928e1477b11040e5c00",  // kPlaneU.
+          "3ce720c2b5b44928e1477b11040e5c00",  // kPlaneV.
+      },
+  };
+  return kDigestSuperRes[id][plane];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetSuperResDigest10bpp(int id, int plane) {
+  // Digests are in Y/U/V order.
+  static const char* const kDigestSuperRes[][kMaxPlanes] = {
+      {
+          // all input is 0.
+          "fccb1f57b252b1a86d335aea929d1d58",
+          "2f244a56091c9705794e92e6bcc38058",
+          "2f244a56091c9705794e92e6bcc38058",
+      },
+      {
+          // all input is 1.
+          "de8556204999d6e4bf74cfdde61a095b",
+          "e7d0f4ce6df81c46de95da7790a67384",
+          "e7d0f4ce6df81c46de95da7790a67384",
+      },
+      {
+          // all input is 512.
+          "d3b6980363eb9b808885537b3485af87",
+          "bcffddb26210da6861e7b31414e58b77",
+          "bcffddb26210da6861e7b31414e58b77",
+      },
+      {
+          // all input is 1023.
+          "ce0762aeee1cdef1db101e4ca39bcbd6",
+          "33aeaa7f5d7c032e3dfda43925c3dcb2",
+          "33aeaa7f5d7c032e3dfda43925c3dcb2",
+      },
+      {
+          // random input.
+          "63c701bceb187ffa535be15ae58f8171",
+          "f570e30e9ea8d2a1e6d99202cd2f8994",
+          "f570e30e9ea8d2a1e6d99202cd2f8994",
+      },
+  };
+  return kDigestSuperRes[id][plane];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetSuperResDigest12bpp(int id, int plane) {
+  // Digests are in Y/U/V order.
+  static const char* const kDigestSuperRes[][kMaxPlanes] = {
+      {
+          // all input is 0.
+          "fccb1f57b252b1a86d335aea929d1d58",
+          "2f244a56091c9705794e92e6bcc38058",
+          "2f244a56091c9705794e92e6bcc38058",
+      },
+      {
+          // all input is 1.
+          "de8556204999d6e4bf74cfdde61a095b",
+          "e7d0f4ce6df81c46de95da7790a67384",
+          "e7d0f4ce6df81c46de95da7790a67384",
+      },
+      {
+          // all input is 2048.
+          "83d600a7b3dc9bc3f710668ee2244e6b",
+          "468eec1453edc1befeb8a346f61950a7",
+          "468eec1453edc1befeb8a346f61950a7",
+      },
+      {
+          // all input is 4095.
+          "30bdb1dfee2b02b12b38e6b9f6287e27",
+          "34d673f075d2caa93a2f648ee3569e20",
+          "34d673f075d2caa93a2f648ee3569e20",
+      },
+      {
+          // random input.
+          "f10f21f5322231d991550fce7ef9787d",
+          "a2d8b6140bd5002e86644ef433b8eb42",
+          "a2d8b6140bd5002e86644ef433b8eb42",
+      },
+  };
+  return kDigestSuperRes[id][plane];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+
+// This type is used to parameterize the tests so is defined outside the
+// anonymous namespace to avoid the GCC -Wsubobject-linkage warning.
+struct FrameSizeParam {
+  FrameSizeParam(uint32_t width, uint32_t upscaled_width, uint32_t height,
+                 int8_t ss_x, int8_t ss_y)
+      : width(width),
+        upscaled_width(upscaled_width),
+        height(height),
+        subsampling_x(ss_x),
+        subsampling_y(ss_y) {}
+  uint32_t width;
+  uint32_t upscaled_width;
+  uint32_t height;
+  int8_t subsampling_x;
+  int8_t subsampling_y;
+};
+
+// Print operators must be defined in the same namespace as the type for the
+// lookup to work correctly.
+static std::ostream& operator<<(std::ostream& os, const FrameSizeParam& param) {
+  return os << param.width << "x" << param.height
+            << ", upscaled_width: " << param.upscaled_width
+            << ", subsampling(x/y): " << static_cast<int>(param.subsampling_x)
+            << "/" << static_cast<int>(param.subsampling_y);
+}
+
+// Note the following test classes access private functions/members of
+// PostFilter. To be declared friends of PostFilter they must not have internal
+// linkage (they must be outside the anonymous namespace).
+template <int bitdepth, typename Pixel>
+class PostFilterTestBase : public testing::TestWithParam<FrameSizeParam> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  PostFilterTestBase() = default;
+  PostFilterTestBase(const PostFilterTestBase&) = delete;
+  PostFilterTestBase& operator=(const PostFilterTestBase&) = delete;
+  ~PostFilterTestBase() override = default;
+
+  void SetUp() override {
+    // Allocate buffer_ with a border size of kBorderPixels (which is
+    // subsampled for chroma planes). Some tests (for loop restoration) only use
+    // the nearest 2 or 3 pixels (for both luma and chroma planes) in the
+    // border.
+    ASSERT_TRUE(buffer_.Realloc(
+        bitdepth, /*is_monochrome=*/false, frame_size_.upscaled_width,
+        frame_size_.height, frame_size_.subsampling_x,
+        frame_size_.subsampling_y, kBorderPixels, kBorderPixels, kBorderPixels,
+        kBorderPixels, nullptr, nullptr, nullptr));
+
+    ASSERT_TRUE(loop_restoration_border_.Realloc(
+        bitdepth, /*is_monochrome=*/false, frame_size_.upscaled_width,
+        frame_size_.height, frame_size_.subsampling_x,
+        frame_size_.subsampling_y, kBorderPixels, kBorderPixels, kBorderPixels,
+        kBorderPixels, nullptr, nullptr, nullptr));
+
+    for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+      const int8_t subsampling_x =
+          (plane == kPlaneY) ? 0 : frame_size_.subsampling_x;
+      const int8_t subsampling_y =
+          (plane == kPlaneY) ? 0 : frame_size_.subsampling_y;
+      width_[plane] = frame_size_.width >> subsampling_x;
+      upscaled_width_[plane] = frame_size_.upscaled_width >> subsampling_x;
+      stride_[plane] =
+          (frame_size_.upscaled_width + 2 * kBorderPixels) >> subsampling_x;
+      height_[plane] =
+          (frame_size_.height + 2 * kBorderPixels) >> subsampling_y;
+
+      reference_buffer_[plane].reserve(stride_[plane] * height_[plane]);
+      reference_buffer_[plane].resize(stride_[plane] * height_[plane]);
+      std::fill(reference_buffer_[plane].begin(),
+                reference_buffer_[plane].end(), 0);
+    }
+  }
+
+ protected:
+  YuvBuffer buffer_;
+  YuvBuffer cdef_border_;
+  YuvBuffer loop_restoration_border_;
+  uint32_t width_[kMaxPlanes];
+  uint32_t upscaled_width_[kMaxPlanes];
+  uint32_t stride_[kMaxPlanes];
+  uint32_t height_[kMaxPlanes];
+  std::vector<Pixel> reference_buffer_[kMaxPlanes];
+  const FrameSizeParam frame_size_ = GetParam();
+};
+
+template <int bitdepth, typename Pixel>
+class PostFilterHelperFuncTest : public PostFilterTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  PostFilterHelperFuncTest() = default;
+  PostFilterHelperFuncTest(const PostFilterHelperFuncTest&) = delete;
+  PostFilterHelperFuncTest& operator=(const PostFilterHelperFuncTest&) = delete;
+  ~PostFilterHelperFuncTest() override = default;
+
+ protected:
+  using PostFilterTestBase<bitdepth, Pixel>::buffer_;
+  using PostFilterTestBase<bitdepth, Pixel>::cdef_border_;
+  using PostFilterTestBase<bitdepth, Pixel>::loop_restoration_border_;
+  using PostFilterTestBase<bitdepth, Pixel>::width_;
+  using PostFilterTestBase<bitdepth, Pixel>::upscaled_width_;
+  using PostFilterTestBase<bitdepth, Pixel>::stride_;
+  using PostFilterTestBase<bitdepth, Pixel>::height_;
+  using PostFilterTestBase<bitdepth, Pixel>::reference_buffer_;
+  using PostFilterTestBase<bitdepth, Pixel>::frame_size_;
+
+  void SetUp() override {
+    PostFilterTestBase<bitdepth, Pixel>::SetUp();
+
+    for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+      const int8_t subsampling_x =
+          (plane == kPlaneY) ? 0 : frame_size_.subsampling_x;
+      const int8_t subsampling_y =
+          (plane == kPlaneY) ? 0 : frame_size_.subsampling_y;
+      width_[plane] = frame_size_.width >> subsampling_x;
+      upscaled_width_[plane] = frame_size_.upscaled_width >> subsampling_x;
+      stride_[plane] = (frame_size_.upscaled_width >> subsampling_x) +
+                       2 * kRestorationHorizontalBorder;
+      height_[plane] = (frame_size_.height >> subsampling_y) +
+                       2 * kRestorationVerticalBorder;
+      reference_buffer_[plane].reserve(stride_[plane] * height_[plane]);
+      reference_buffer_[plane].resize(stride_[plane] * height_[plane]);
+      std::fill(reference_buffer_[plane].begin(),
+                reference_buffer_[plane].end(), 0);
+      buffer_border_corner_[plane] =
+          reinterpret_cast<Pixel*>(buffer_.data(plane)) -
+          buffer_.stride(plane) / sizeof(Pixel) * kRestorationVerticalBorder -
+          kRestorationHorizontalBorder;
+      loop_restoration_border_corner_[plane] =
+          reinterpret_cast<Pixel*>(loop_restoration_border_.data(plane)) -
+          loop_restoration_border_.stride(plane) / sizeof(Pixel) *
+              kRestorationVerticalBorder -
+          kRestorationHorizontalBorder;
+    }
+  }
+
+  void TestExtendFrame(bool use_fixed_values, Pixel value);
+  void TestAdjustFrameBufferPointer();
+  void TestPrepareLoopRestorationBlock();
+
+  // Fill the frame buffer with either a fixed value, or random values.
+  // If fill in with random values, make special operations at buffer
+  // boundaries. Make the outer most 3 pixel wide borders the same value
+  // as their immediate inner neighbor. For example:
+  // 4 4 4   4 5 6   6 6 6
+  // 4 4 4   4 5 6   6 6 6
+  // 4 4 4   4 5 6   6 6 6
+  //       ---------
+  // 4 4 4 | 4 5 6 | 6 6 6
+  // 1 1 1 | 1 0 1 | 1 1 1
+  // 0 0 0 | 0 1 0 | 0 0 0
+  // 1 1 1 | 1 0 1 | 1 1 1
+  // 0 0 0 | 0 1 0 | 0 0 0
+  // 6 6 6 | 6 5 4 | 4 4 4
+  //        -------
+  // 6 6 6   6 5 4   4 4 4
+  // 6 6 6   6 5 4   4 4 4
+  // 6 6 6   6 5 4   4 4 4
+  // Pixels within box is the current block. Outside is extended area from it.
+  void FillBuffer(bool use_fixed_values, Pixel value);
+
+  // Points to the upper left corner of the restoration border in buffer_.
+  Pixel* buffer_border_corner_[kMaxPlanes];
+  // Points to the upper left corner of the restoration border in
+  // loop_restoration_border_.
+  Pixel* loop_restoration_border_corner_[kMaxPlanes];
+};
+
+template <int bitdepth, typename Pixel>
+void PostFilterHelperFuncTest<bitdepth, Pixel>::FillBuffer(
+    bool use_fixed_values, Pixel value) {
+  if (use_fixed_values) {
+    for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+      // Fill buffer with a fixed value.
+      std::fill(reference_buffer_[plane].begin(),
+                reference_buffer_[plane].end(), value);
+      // Fill frame buffer. Note that the border is not filled.
+      auto* row = reinterpret_cast<Pixel*>(buffer_.data(plane));
+      for (int i = 0; i < buffer_.height(plane); ++i) {
+        std::fill(row, row + width_[plane], value);
+        row += buffer_.stride(plane) / sizeof(Pixel);
+      }
+    }
+  } else {  // Random value.
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    const int mask = (1 << bitdepth) - 1;
+    for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+      // Fill buffer with random values.
+      std::vector<Pixel> line_buffer(stride_[plane]);
+      std::fill(line_buffer.begin(), line_buffer.end(), 0);
+      for (int i = kRestorationHorizontalBorder;
+           i < stride_[plane] - kRestorationHorizontalBorder; ++i) {
+        line_buffer[i] = rnd.Rand16() & mask;
+      }
+      // Copy boundary values to extended border.
+      for (int i = 0; i < kRestorationHorizontalBorder; ++i) {
+        line_buffer[i] = line_buffer[kRestorationHorizontalBorder];
+        line_buffer[stride_[plane] - i - 1] =
+            line_buffer[stride_[plane] - 1 - kRestorationHorizontalBorder];
+      }
+      // The first three rows are the same as the line_buffer.
+      for (int i = 0; i < kRestorationVerticalBorder + 1; ++i) {
+        std::copy(line_buffer.begin(), line_buffer.end(),
+                  reference_buffer_[plane].begin() + i * stride_[plane]);
+      }
+      for (int i = kRestorationVerticalBorder + 1;
+           i < height_[plane] - kRestorationVerticalBorder; ++i) {
+        for (int j = kRestorationHorizontalBorder;
+             j < stride_[plane] - kRestorationHorizontalBorder; ++j) {
+          line_buffer[j] = rnd.Rand16() & mask;
+        }
+        for (int j = 0; j < kRestorationHorizontalBorder; ++j) {
+          line_buffer[j] = line_buffer[kRestorationHorizontalBorder];
+          line_buffer[stride_[plane] - j - 1] =
+              line_buffer[stride_[plane] - 1 - kRestorationHorizontalBorder];
+        }
+        std::copy(line_buffer.begin(), line_buffer.end(),
+                  reference_buffer_[plane].begin() + i * stride_[plane]);
+      }
+      // The extended border are the same as the line_buffer.
+      for (int i = 0; i < kRestorationVerticalBorder; ++i) {
+        std::copy(line_buffer.begin(), line_buffer.end(),
+                  reference_buffer_[plane].begin() +
+                      (height_[plane] - kRestorationVerticalBorder + i) *
+                          stride_[plane]);
+      }
+
+      // Fill frame buffer. Note that the border is not filled.
+      for (int i = 0; i < buffer_.height(plane); ++i) {
+        memcpy(buffer_.data(plane) + i * buffer_.stride(plane),
+               reference_buffer_[plane].data() + kRestorationHorizontalBorder +
+                   (i + kRestorationVerticalBorder) * stride_[plane],
+               sizeof(Pixel) * width_[plane]);
+      }
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void PostFilterHelperFuncTest<bitdepth, Pixel>::TestExtendFrame(
+    bool use_fixed_values, Pixel value) {
+  ObuFrameHeader frame_header = {};
+  frame_header.upscaled_width = frame_size_.upscaled_width;
+  frame_header.width = frame_size_.width;
+  frame_header.height = frame_size_.height;
+  ObuSequenceHeader sequence_header;
+  sequence_header.color_config.bitdepth = bitdepth;
+  sequence_header.color_config.is_monochrome = false;
+  sequence_header.color_config.subsampling_x = frame_size_.subsampling_x;
+  sequence_header.color_config.subsampling_y = frame_size_.subsampling_y;
+
+  const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+  ASSERT_NE(dsp, nullptr);
+  FrameScratchBuffer frame_scratch_buffer;
+
+  PostFilter post_filter(frame_header, sequence_header, &frame_scratch_buffer,
+                         &buffer_, dsp,
+                         /*do_post_filter_mask=*/0x00);
+  FillBuffer(use_fixed_values, value);
+  for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+    const int plane_width =
+        plane == kPlaneY ? frame_header.upscaled_width
+                         : frame_header.upscaled_width >>
+                               sequence_header.color_config.subsampling_x;
+    const int plane_height =
+        plane == kPlaneY
+            ? frame_header.height
+            : frame_header.height >> sequence_header.color_config.subsampling_y;
+    PostFilter::ExtendFrame<Pixel>(
+        reinterpret_cast<Pixel*>(buffer_.data(plane)), plane_width,
+        plane_height, buffer_.stride(plane) / sizeof(Pixel),
+        kRestorationHorizontalBorder, kRestorationHorizontalBorder,
+        kRestorationVerticalBorder, kRestorationVerticalBorder);
+    const bool success = test_utils::CompareBlocks<Pixel>(
+        buffer_border_corner_[plane], reference_buffer_[plane].data(),
+        stride_[plane], height_[plane], buffer_.stride(plane) / sizeof(Pixel),
+        stride_[plane], /*check_padding=*/false, /*print_diff=*/false);
+    ASSERT_TRUE(success) << "Failure of extend frame at plane: " << plane;
+  }
+}
+
+template <int bitdepth, typename Pixel>
+class PostFilterSuperResTest : public PostFilterTestBase<bitdepth, Pixel> {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  PostFilterSuperResTest() {
+    test_utils::ResetDspTable(bitdepth);
+    dsp::SuperResInit_C();
+    dsp::SuperResInit_SSE4_1();
+    dsp::SuperResInit_NEON();
+  }
+  PostFilterSuperResTest(const PostFilterSuperResTest&) = delete;
+  PostFilterSuperResTest& operator=(const PostFilterSuperResTest&) = delete;
+  ~PostFilterSuperResTest() override = default;
+
+ protected:
+  using PostFilterTestBase<bitdepth, Pixel>::buffer_;
+  using PostFilterTestBase<bitdepth, Pixel>::width_;
+  using PostFilterTestBase<bitdepth, Pixel>::upscaled_width_;
+  using PostFilterTestBase<bitdepth, Pixel>::stride_;
+  using PostFilterTestBase<bitdepth, Pixel>::height_;
+  using PostFilterTestBase<bitdepth, Pixel>::reference_buffer_;
+  using PostFilterTestBase<bitdepth, Pixel>::frame_size_;
+
+  void TestApplySuperRes(bool use_fixed_values, Pixel value, int id,
+                         bool multi_threaded);
+};
+
+// This class must be in namespace libgav1 to access private member function
+// of class PostFilter in src/post_filter.h.
+template <int bitdepth, typename Pixel>
+void PostFilterSuperResTest<bitdepth, Pixel>::TestApplySuperRes(
+    bool use_fixed_values, Pixel value, int id, bool multi_threaded) {
+  ObuFrameHeader frame_header = {};
+  frame_header.width = frame_size_.width;
+  frame_header.upscaled_width = frame_size_.upscaled_width;
+  frame_header.height = frame_size_.height;
+  frame_header.rows4x4 = DivideBy4(frame_size_.height);
+  frame_header.columns4x4 = DivideBy4(frame_size_.width);
+  frame_header.tile_info.tile_count = 1;
+  ObuSequenceHeader sequence_header;
+  sequence_header.color_config.bitdepth = bitdepth;
+  sequence_header.color_config.is_monochrome = false;
+  sequence_header.color_config.subsampling_x = frame_size_.subsampling_x;
+  sequence_header.color_config.subsampling_y = frame_size_.subsampling_y;
+
+  // Apply SuperRes.
+  Array2D<int16_t> cdef_index;
+  Array2D<TransformSize> inter_transform_sizes;
+  const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
+  ASSERT_NE(dsp, nullptr);
+  constexpr int kNumThreads = 4;
+  FrameScratchBuffer frame_scratch_buffer;
+  if (multi_threaded) {
+    ASSERT_TRUE(frame_scratch_buffer.threading_strategy.Reset(frame_header,
+                                                              kNumThreads));
+  }
+  const int pixel_size = sequence_header.color_config.bitdepth == 8
+                             ? sizeof(uint8_t)
+                             : sizeof(uint16_t);
+  ASSERT_TRUE(frame_scratch_buffer.superres_coefficients[kPlaneTypeY].Resize(
+      kSuperResFilterTaps * Align(frame_header.upscaled_width, 16) *
+      pixel_size));
+  if (!sequence_header.color_config.is_monochrome &&
+      sequence_header.color_config.subsampling_x != 0) {
+    ASSERT_TRUE(frame_scratch_buffer.superres_coefficients[kPlaneTypeUV].Resize(
+        kSuperResFilterTaps *
+        Align(SubsampledValue(frame_header.upscaled_width, 1), 16) *
+        pixel_size));
+  }
+  ASSERT_TRUE(frame_scratch_buffer.superres_line_buffer.Realloc(
+      sequence_header.color_config.bitdepth,
+      sequence_header.color_config.is_monochrome,
+      MultiplyBy4(frame_header.columns4x4), (multi_threaded ? kNumThreads : 1),
+      sequence_header.color_config.subsampling_x,
+      /*subsampling_y=*/0, 2 * kSuperResHorizontalBorder,
+      2 * (kSuperResHorizontalBorder + kSuperResHorizontalPadding), 0, 0,
+      nullptr, nullptr, nullptr));
+  PostFilter post_filter(frame_header, sequence_header, &frame_scratch_buffer,
+                         &buffer_, dsp,
+                         /*do_post_filter_mask=*/0x04);
+
+  const int num_planes = sequence_header.color_config.is_monochrome
+                             ? kMaxPlanesMonochrome
+                             : kMaxPlanes;
+  int width[kMaxPlanes];
+  int upscaled_width[kMaxPlanes];
+  int height[kMaxPlanes];
+
+  for (int plane = kPlaneY; plane < num_planes; ++plane) {
+    const int8_t subsampling_x =
+        (plane == kPlaneY) ? 0 : frame_size_.subsampling_x;
+    const int8_t subsampling_y =
+        (plane == kPlaneY) ? 0 : frame_size_.subsampling_y;
+    width[plane] = frame_size_.width >> subsampling_x;
+    upscaled_width[plane] = frame_size_.upscaled_width >> subsampling_x;
+    height[plane] = frame_size_.height >> subsampling_y;
+    if (use_fixed_values) {
+      auto* src = reinterpret_cast<Pixel*>(post_filter.cdef_buffer_[plane]);
+      for (int y = 0; y < height[plane]; ++y) {
+        for (int x = 0; x < width[plane]; ++x) {
+          src[x] = value;
+        }
+        src += buffer_.stride(plane) / sizeof(Pixel);
+      }
+    } else {  // Random input.
+      const int mask = (1 << bitdepth) - 1;
+      libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+      auto* src = reinterpret_cast<Pixel*>(post_filter.cdef_buffer_[plane]);
+      for (int y = 0; y < height[plane]; ++y) {
+        for (int x = 0; x < width[plane]; ++x) {
+          src[x] = rnd.Rand16() & mask;
+        }
+        src += buffer_.stride(plane) / sizeof(Pixel);
+      }
+    }
+  }
+
+  if (multi_threaded) {
+    post_filter.ApplySuperResThreaded();
+  } else {
+    std::array<uint8_t*, kMaxPlanes> buffers = {
+        post_filter.cdef_buffer_[kPlaneY], post_filter.cdef_buffer_[kPlaneU],
+        post_filter.cdef_buffer_[kPlaneV]};
+    std::array<uint8_t*, kMaxPlanes> dst = {
+        post_filter.GetSuperResBuffer(static_cast<Plane>(kPlaneY), 0, 0),
+        post_filter.GetSuperResBuffer(static_cast<Plane>(kPlaneU), 0, 0),
+        post_filter.GetSuperResBuffer(static_cast<Plane>(kPlaneV), 0, 0)};
+    std::array<int, kMaxPlanes> rows = {
+        frame_header.rows4x4 * 4,
+        (frame_header.rows4x4 * 4) >> frame_size_.subsampling_y,
+        (frame_header.rows4x4 * 4) >> frame_size_.subsampling_y};
+    post_filter.ApplySuperRes(buffers, rows, /*line_buffer_row=*/-1, dst);
+  }
+
+  // Check md5.
+  std::vector<Pixel> output;
+  for (int plane = kPlaneY; plane < num_planes; ++plane) {
+    output.reserve(upscaled_width[plane] * height[plane]);
+    output.resize(upscaled_width[plane] * height[plane]);
+    auto* dst = reinterpret_cast<Pixel*>(
+        post_filter.GetSuperResBuffer(static_cast<Plane>(plane), 0, 0));
+    for (int y = 0; y < height[plane]; ++y) {
+      for (int x = 0; x < upscaled_width[plane]; ++x) {
+        output[y * upscaled_width[plane] + x] = dst[x];
+      }
+      dst += buffer_.stride(plane) / sizeof(Pixel);
+    }
+    const std::string digest = test_utils::GetMd5Sum(
+        output.data(), upscaled_width[plane] * height[plane] * sizeof(Pixel));
+    printf("MD5: %s\n", digest.c_str());
+    const char* expected_digest = nullptr;
+    switch (bitdepth) {
+      case 8:
+        expected_digest = GetSuperResDigest8bpp(id, plane);
+        break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+      case 10:
+        expected_digest = GetSuperResDigest10bpp(id, plane);
+        break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+      case 12:
+        expected_digest = GetSuperResDigest12bpp(id, plane);
+        break;
+#endif
+    }
+    ASSERT_NE(expected_digest, nullptr);
+    EXPECT_STREQ(digest.c_str(), expected_digest);
+  }
+}
+
+using PostFilterSuperResTest8bpp = PostFilterSuperResTest<8, uint8_t>;
+
+const FrameSizeParam kTestParamSuperRes[] = {
+    FrameSizeParam(176, 352, 288, 1, 1)};
+
+TEST_P(PostFilterSuperResTest8bpp, ApplySuperRes) {
+  TestApplySuperRes(true, 0, 0, false);
+  TestApplySuperRes(true, 1, 1, false);
+  TestApplySuperRes(true, 128, 2, false);
+  TestApplySuperRes(true, 255, 3, false);
+  TestApplySuperRes(false, 0, 4, false);
+}
+
+TEST_P(PostFilterSuperResTest8bpp, ApplySuperResThreaded) {
+  TestApplySuperRes(true, 0, 0, true);
+  TestApplySuperRes(true, 1, 1, true);
+  TestApplySuperRes(true, 128, 2, true);
+  TestApplySuperRes(true, 255, 3, true);
+  TestApplySuperRes(false, 0, 4, true);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterSuperResTestInstance,
+                         PostFilterSuperResTest8bpp,
+                         testing::ValuesIn(kTestParamSuperRes));
+
+using PostFilterHelperFuncTest8bpp = PostFilterHelperFuncTest<8, uint8_t>;
+
+const FrameSizeParam kTestParamExtendFrame[] = {
+    FrameSizeParam(16, 16, 16, 1, 1),
+    FrameSizeParam(64, 64, 64, 1, 1),
+    FrameSizeParam(128, 128, 64, 1, 1),
+    FrameSizeParam(64, 64, 128, 1, 1),
+    FrameSizeParam(352, 352, 288, 1, 1),
+    FrameSizeParam(720, 720, 480, 1, 1),
+    FrameSizeParam(1080, 1080, 720, 1, 1),
+    FrameSizeParam(16, 16, 16, 0, 0),
+    FrameSizeParam(64, 64, 64, 0, 0),
+    FrameSizeParam(128, 128, 64, 0, 0),
+    FrameSizeParam(64, 64, 128, 0, 0),
+    FrameSizeParam(352, 352, 288, 0, 0),
+    FrameSizeParam(720, 720, 480, 0, 0),
+    FrameSizeParam(1080, 1080, 720, 0, 0)};
+
+TEST_P(PostFilterHelperFuncTest8bpp, ExtendFrame) {
+  TestExtendFrame(true, 0);
+  TestExtendFrame(true, 1);
+  TestExtendFrame(true, 128);
+  TestExtendFrame(true, 255);
+  TestExtendFrame(false, 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterHelperFuncTestInstance,
+                         PostFilterHelperFuncTest8bpp,
+                         testing::ValuesIn(kTestParamExtendFrame));
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using PostFilterSuperResTest10bpp = PostFilterSuperResTest<10, uint16_t>;
+
+TEST_P(PostFilterSuperResTest10bpp, ApplySuperRes) {
+  TestApplySuperRes(true, 0, 0, false);
+  TestApplySuperRes(true, 1, 1, false);
+  TestApplySuperRes(true, 1 << 9, 2, false);
+  TestApplySuperRes(true, (1 << 10) - 1, 3, false);
+  TestApplySuperRes(false, 0, 4, false);
+}
+
+TEST_P(PostFilterSuperResTest10bpp, ApplySuperResThreaded) {
+  TestApplySuperRes(true, 0, 0, true);
+  TestApplySuperRes(true, 1, 1, true);
+  TestApplySuperRes(true, 1 << 9, 2, true);
+  TestApplySuperRes(true, (1 << 10) - 1, 3, true);
+  TestApplySuperRes(false, 0, 4, true);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterSuperResTestInstance,
+                         PostFilterSuperResTest10bpp,
+                         testing::ValuesIn(kTestParamSuperRes));
+
+using PostFilterHelperFuncTest10bpp = PostFilterHelperFuncTest<10, uint16_t>;
+
+TEST_P(PostFilterHelperFuncTest10bpp, ExtendFrame) {
+  TestExtendFrame(true, 0);
+  TestExtendFrame(true, 1);
+  TestExtendFrame(true, 255);
+  TestExtendFrame(true, (1 << 10) - 1);
+  TestExtendFrame(false, 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterHelperFuncTestInstance,
+                         PostFilterHelperFuncTest10bpp,
+                         testing::ValuesIn(kTestParamExtendFrame));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using PostFilterSuperResTest12bpp = PostFilterSuperResTest<12, uint16_t>;
+
+TEST_P(PostFilterSuperResTest12bpp, ApplySuperRes) {
+  TestApplySuperRes(true, 0, 0, false);
+  TestApplySuperRes(true, 1, 1, false);
+  TestApplySuperRes(true, 1 << 11, 2, false);
+  TestApplySuperRes(true, (1 << 12) - 1, 3, false);
+  TestApplySuperRes(false, 0, 4, false);
+}
+
+TEST_P(PostFilterSuperResTest12bpp, ApplySuperResThreaded) {
+  TestApplySuperRes(true, 0, 0, true);
+  TestApplySuperRes(true, 1, 1, true);
+  TestApplySuperRes(true, 1 << 11, 2, true);
+  TestApplySuperRes(true, (1 << 12) - 1, 3, true);
+  TestApplySuperRes(false, 0, 4, true);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterSuperResTestInstance,
+                         PostFilterSuperResTest12bpp,
+                         testing::ValuesIn(kTestParamSuperRes));
+
+using PostFilterHelperFuncTest12bpp = PostFilterHelperFuncTest<12, uint16_t>;
+
+TEST_P(PostFilterHelperFuncTest12bpp, ExtendFrame) {
+  TestExtendFrame(true, 0);
+  TestExtendFrame(true, 1);
+  TestExtendFrame(true, 255);
+  TestExtendFrame(true, (1 << 12) - 1);
+  TestExtendFrame(false, 0);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterHelperFuncTestInstance,
+                         PostFilterHelperFuncTest12bpp,
+                         testing::ValuesIn(kTestParamExtendFrame));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+namespace {
+
+const char* GetDigestApplyCdef8bpp(int id) {
+  static const char* const kDigest[] = {
+      "9593af24f9c6faecce53437f6e128edf", "ecb633cc2ecd6e7e0cf39d4439f4a6ea",
+      "9ec4cb4124f0a686a7bda72b447f5b8e", "7ebd859a23162bc864a69dbea60bc687",
+      "de7a15fc00664692a794aa68cf695980", "cf3fc8fe041f68d31ab4e34ad3643541",
+      "94c116b191b0268cf7ab4a0e6996e1ec", "1ad60c943a5a914aba7bc26706620a05",
+      "ce33c6f80e3608c4d18c49be2e393c20", "e140586ffc663798b74b8f6fb5b44736",
+      "b7379bba8bcb97f09a74655f4e0eee91", "02ce174061c98babd3987461b3984e47",
+      "64655dd1dfba8317e27d2fdcb211b7b4", "eeb6a61c70c5ee75a4c31dc5099b4dfb",
+      "ee944b31148fa2e30938084f7c046464", "db7b63497750fa4c51cf45c56a2da01c",
+  };
+  return kDigest[id];
+}
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+const char* GetDigestApplyCdef10bpp(int id) {
+  static const char* const kDigest[] = {
+      "53f8d68ac7f3aea65151b2066f8501c9", "021e70d5406fa182dd9713380eb66d1d",
+      "bab1c84e7f06b87d81617d2d0a194b89", "58e302ff0522f64901909fb97535b270",
+      "5ff95a6a798eadc7207793c03d898ce4", "1483d28cc0f1bfffedd1128966719aa0",
+      "6af5a36890b465ae962c2878af874f70", "bd1ed4a2ff09d323ab98190d1805a010",
+      "5ff95a6a798eadc7207793c03d898ce4", "1483d28cc0f1bfffedd1128966719aa0",
+      "6af5a36890b465ae962c2878af874f70", "bd1ed4a2ff09d323ab98190d1805a010",
+      "6f0299645cd6f0655fd26044cd43a37c", "56d7febf5bbebdc82e8f157ab926a0bb",
+      "f54654f11006453f496be5883216a3bb", "9abc6e3230792ba78bcc65504a62075e",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+const char* GetDigestApplyCdef12bpp(int id) {
+  static const char* const kDigest[] = {
+      "06e2d09b6ce3924f3b5d4c00ab76eea5", "287240e4b13cb75e17932a3dd7ba3b3c",
+      "265da123e3347c4fb3e434f26a3949e7", "e032ce6eb76242df6894482ac6688406",
+      "f648328221f0f02a5b7fc3d55a66271a", "8f759aa84a110902025dacf8062d2f6a",
+      "592b49e4b993d6b4634d8eb1ee3bba54", "29a3e8e329ec70d06910e982ea763e6b",
+      "f648328221f0f02a5b7fc3d55a66271a", "8f759aa84a110902025dacf8062d2f6a",
+      "592b49e4b993d6b4634d8eb1ee3bba54", "29a3e8e329ec70d06910e982ea763e6b",
+      "155dd4283f8037f86cce34b6cfe67a7e", "0a022c70ead199517af9bad2002d70cd",
+      "a966dfea52a7a2084545f68b2c9e1735", "e098438a23a7c9f276e594b98b2db922",
+  };
+  return kDigest[id];
+}
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace
+
+template <int bitdepth, typename Pixel>
+class PostFilterApplyCdefTest : public testing::TestWithParam<FrameSizeParam>,
+                                public test_utils::MaxAlignedAllocable {
+ public:
+  static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
+  PostFilterApplyCdefTest() = default;
+  PostFilterApplyCdefTest(const PostFilterApplyCdefTest&) = delete;
+  PostFilterApplyCdefTest& operator=(const PostFilterApplyCdefTest&) = delete;
+  ~PostFilterApplyCdefTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(bitdepth);
+    dsp::CdefInit_C();
+    dsp::CdefInit_SSE4_1();
+    dsp::CdefInit_NEON();
+
+    dsp_ = dsp::GetDspTable(bitdepth);
+    ASSERT_NE(dsp_, nullptr);
+  }
+
+  // Sets sequence_header_, frame_header_, cdef_index_ and cdef_skip_.
+  // Allocates yuv_buffer_ but does not set it.
+  void SetInput(libvpx_test::ACMRandom* rnd);
+  // Sets yuv_buffer_.
+  void SetInputBuffer(libvpx_test::ACMRandom* rnd, PostFilter* post_filter);
+  void CopyFilterOutputToDestBuffer();
+  void TestMultiThread(int num_threads);
+
+  ObuSequenceHeader sequence_header_;
+  ObuFrameHeader frame_header_ = {};
+  FrameScratchBuffer frame_scratch_buffer_;
+  YuvBuffer yuv_buffer_;
+  const dsp::Dsp* dsp_;
+  FrameSizeParam param_ = GetParam();
+  Pixel dest_[kMaxTestFrameSize * kMaxPlanes];
+  const size_t y_size_ = param_.width * param_.height;
+  const size_t uv_size_ = y_size_ >>
+                          (param_.subsampling_x + param_.subsampling_y);
+  const size_t size_ = y_size_ + uv_size_ * 2;
+};
+
+template <int bitdepth, typename Pixel>
+void PostFilterApplyCdefTest<bitdepth, Pixel>::SetInput(
+    libvpx_test::ACMRandom* rnd) {
+  sequence_header_.color_config.bitdepth = bitdepth;
+  sequence_header_.color_config.subsampling_x = param_.subsampling_x;
+  sequence_header_.color_config.subsampling_y = param_.subsampling_y;
+  sequence_header_.color_config.is_monochrome = false;
+  sequence_header_.use_128x128_superblock =
+      static_cast<bool>(rnd->Rand16() & 1);
+
+  ASSERT_TRUE(param_.width <= param_.upscaled_width);
+  ASSERT_TRUE(param_.upscaled_width * param_.height <= kMaxTestFrameSize)
+      << "Please adjust the max frame size.";
+
+  frame_header_.width = param_.width;
+  frame_header_.upscaled_width = param_.upscaled_width;
+  frame_header_.height = param_.height;
+  frame_header_.columns4x4 = DivideBy4(Align(frame_header_.width, 8));
+  frame_header_.rows4x4 = DivideBy4(Align(frame_header_.height, 8));
+  frame_header_.tile_info.tile_count = 1;
+  frame_header_.refresh_frame_flags = 0;
+  Cdef* const cdef = &frame_header_.cdef;
+  const int coeff_shift = bitdepth - 8;
+  do {
+    cdef->damping = (rnd->Rand16() & 3) + 3 + coeff_shift;
+    cdef->bits = rnd->Rand16() & 3;
+  } while (cdef->bits <= 0);
+  for (int i = 0; i < (1 << cdef->bits); ++i) {
+    cdef->y_primary_strength[i] = (rnd->Rand16() & 15) << coeff_shift;
+    cdef->y_secondary_strength[i] = rnd->Rand16() & 3;
+    if (cdef->y_secondary_strength[i] == 3) {
+      ++cdef->y_secondary_strength[i];
+    }
+    cdef->y_secondary_strength[i] <<= coeff_shift;
+    cdef->uv_primary_strength[i] = (rnd->Rand16() & 15) << coeff_shift;
+    cdef->uv_secondary_strength[i] = rnd->Rand16() & 3;
+    if (cdef->uv_secondary_strength[i] == 3) {
+      ++cdef->uv_secondary_strength[i];
+    }
+    cdef->uv_secondary_strength[i] <<= coeff_shift;
+  }
+
+  const int rows64x64 = DivideBy16(frame_header_.rows4x4 + kMaxBlockHeight4x4);
+  const int columns64x64 =
+      DivideBy16(frame_header_.columns4x4 + kMaxBlockWidth4x4);
+  ASSERT_TRUE(frame_scratch_buffer_.cdef_index.Reset(rows64x64, columns64x64));
+  for (int row = 0; row < rows64x64; ++row) {
+    for (int column = 0; column < columns64x64; ++column) {
+      frame_scratch_buffer_.cdef_index[row][column] =
+          rnd->Rand16() & ((1 << cdef->bits) - 1);
+    }
+  }
+
+  const int skip_rows = DivideBy2(frame_header_.rows4x4 + kMaxBlockHeight4x4);
+  const int skip_columns =
+      DivideBy16(frame_header_.columns4x4 + kMaxBlockWidth4x4);
+  ASSERT_TRUE(frame_scratch_buffer_.cdef_skip.Reset(skip_rows, skip_columns));
+  for (int row = 0; row < skip_rows; ++row) {
+    memset(frame_scratch_buffer_.cdef_skip[row], 0xFF, skip_columns);
+  }
+
+  ASSERT_TRUE(yuv_buffer_.Realloc(
+      sequence_header_.color_config.bitdepth,
+      sequence_header_.color_config.is_monochrome, frame_header_.upscaled_width,
+      frame_header_.height, sequence_header_.color_config.subsampling_x,
+      sequence_header_.color_config.subsampling_y, kBorderPixels, kBorderPixels,
+      kBorderPixels, kBorderPixels, nullptr, nullptr, nullptr))
+      << "Failed to allocate source buffer.";
+}
+
+template <int bitdepth, typename Pixel>
+void PostFilterApplyCdefTest<bitdepth, Pixel>::SetInputBuffer(
+    libvpx_test::ACMRandom* rnd, PostFilter* post_filter) {
+  for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+    const int subsampling_x = (plane == 0) ? 0 : param_.subsampling_x;
+    const int subsampling_y = (plane == 0) ? 0 : param_.subsampling_y;
+    const int plane_width =
+        MultiplyBy4(frame_header_.columns4x4) >> subsampling_x;
+    const int plane_height =
+        MultiplyBy4(frame_header_.rows4x4) >> subsampling_y;
+    auto* src =
+        reinterpret_cast<Pixel*>(post_filter->GetUnfilteredBuffer(plane));
+    const int src_stride = yuv_buffer_.stride(plane) / sizeof(src[0]);
+    for (int y = 0; y < plane_height; ++y) {
+      for (int x = 0; x < plane_width; ++x) {
+        src[x] = rnd->Rand16() & ((1 << bitdepth) - 1);
+      }
+      src += src_stride;
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void PostFilterApplyCdefTest<bitdepth, Pixel>::CopyFilterOutputToDestBuffer() {
+  for (int plane = kPlaneY; plane < kMaxPlanes; ++plane) {
+    const int subsampling_x = (plane == 0) ? 0 : param_.subsampling_x;
+    const int subsampling_y = (plane == 0) ? 0 : param_.subsampling_y;
+    const int plane_width = SubsampledValue(param_.width, subsampling_x);
+    const int plane_height = SubsampledValue(param_.height, subsampling_y);
+    auto* src = reinterpret_cast<Pixel*>(yuv_buffer_.data(plane));
+    const int src_stride = yuv_buffer_.stride(plane) / sizeof(src[0]);
+    Pixel* dest_plane =
+        dest_ +
+        ((plane == 0) ? 0 : ((plane == 1) ? y_size_ : y_size_ + uv_size_));
+    for (int y = 0; y < plane_height; ++y) {
+      for (int x = 0; x < plane_width; ++x) {
+        dest_plane[y * plane_width + x] = src[x];
+      }
+      src += src_stride;
+    }
+  }
+}
+
+template <int bitdepth, typename Pixel>
+void PostFilterApplyCdefTest<bitdepth, Pixel>::TestMultiThread(
+    int num_threads) {
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  SetInput(&rnd);
+
+  ASSERT_TRUE(frame_scratch_buffer_.threading_strategy.Reset(frame_header_,
+                                                             num_threads));
+  if (num_threads > 1) {
+    const int num_units =
+        MultiplyBy4(RightShiftWithCeiling(frame_header_.rows4x4, 4));
+    ASSERT_TRUE(frame_scratch_buffer_.cdef_border.Realloc(
+        bitdepth, /*is_monochrome=*/false,
+        MultiplyBy4(frame_header_.columns4x4), num_units,
+        sequence_header_.color_config.subsampling_x,
+        /*subsampling_y=*/0, kBorderPixels, kBorderPixels, kBorderPixels,
+        kBorderPixels, nullptr, nullptr, nullptr));
+  }
+
+  PostFilter post_filter(frame_header_, sequence_header_,
+                         &frame_scratch_buffer_, &yuv_buffer_, dsp_,
+                         /*do_post_filter_mask=*/0x02);
+  SetInputBuffer(&rnd, &post_filter);
+
+  const int id = GetIdFromInputParam(param_.subsampling_x, param_.subsampling_y,
+                                     param_.height);
+  absl::Duration elapsed_time;
+  const absl::Time start = absl::Now();
+
+  // Only ApplyCdef() and frame copy inside ApplyFilteringThreaded() are
+  // triggered, since we set the filter mask to 0x02.
+  post_filter.ApplyFilteringThreaded();
+  elapsed_time += absl::Now() - start;
+
+  CopyFilterOutputToDestBuffer();
+  const char* expected_digest = nullptr;
+  switch (bitdepth) {
+    case 8:
+      expected_digest = GetDigestApplyCdef8bpp(id);
+      break;
+#if LIBGAV1_MAX_BITDEPTH >= 10
+    case 10:
+      expected_digest = GetDigestApplyCdef10bpp(id);
+      break;
+#endif
+#if LIBGAV1_MAX_BITDEPTH == 12
+    case 12:
+      expected_digest = GetDigestApplyCdef12bpp(id);
+      break;
+#endif
+  }
+  ASSERT_NE(expected_digest, nullptr);
+  test_utils::CheckMd5Digest(kCdef, kApplyCdefName, expected_digest, dest_,
+                             size_, elapsed_time);
+}
+
+const FrameSizeParam kTestParamApplyCdef[] = {
+    FrameSizeParam(352, 352, 288, 0, 0),    FrameSizeParam(720, 720, 480, 0, 0),
+    FrameSizeParam(1920, 1920, 1080, 0, 0), FrameSizeParam(251, 251, 187, 0, 0),
+    FrameSizeParam(352, 352, 288, 0, 1),    FrameSizeParam(720, 720, 480, 0, 1),
+    FrameSizeParam(1920, 1920, 1080, 0, 1), FrameSizeParam(251, 251, 187, 0, 1),
+    FrameSizeParam(352, 352, 288, 1, 0),    FrameSizeParam(720, 720, 480, 1, 0),
+    FrameSizeParam(1920, 1920, 1080, 1, 0), FrameSizeParam(251, 251, 187, 1, 0),
+    FrameSizeParam(352, 352, 288, 1, 1),    FrameSizeParam(720, 720, 480, 1, 1),
+    FrameSizeParam(1920, 1920, 1080, 1, 1), FrameSizeParam(251, 251, 187, 1, 1),
+};
+
+using PostFilterApplyCdefTest8bpp = PostFilterApplyCdefTest<8, uint8_t>;
+
+TEST_P(PostFilterApplyCdefTest8bpp, ApplyCdef) {
+  TestMultiThread(2);
+  TestMultiThread(4);
+  TestMultiThread(8);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterApplyCdefTestInstance,
+                         PostFilterApplyCdefTest8bpp,
+                         testing::ValuesIn(kTestParamApplyCdef));
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+using PostFilterApplyCdefTest10bpp = PostFilterApplyCdefTest<10, uint16_t>;
+
+TEST_P(PostFilterApplyCdefTest10bpp, ApplyCdef) {
+  TestMultiThread(2);
+  TestMultiThread(4);
+  TestMultiThread(8);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterApplyCdefTestInstance,
+                         PostFilterApplyCdefTest10bpp,
+                         testing::ValuesIn(kTestParamApplyCdef));
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+using PostFilterApplyCdefTest12bpp = PostFilterApplyCdefTest<12, uint16_t>;
+
+TEST_P(PostFilterApplyCdefTest12bpp, ApplyCdef) {
+  TestMultiThread(2);
+  TestMultiThread(4);
+  TestMultiThread(8);
+}
+
+INSTANTIATE_TEST_SUITE_P(PostFilterApplyCdefTestInstance,
+                         PostFilterApplyCdefTest12bpp,
+                         testing::ValuesIn(kTestParamApplyCdef));
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+
+}  // namespace libgav1
diff --git a/src/prediction_mask_test.cc b/src/prediction_mask_test.cc
new file mode 100644
index 0000000..d2a12c2
--- /dev/null
+++ b/src/prediction_mask_test.cc
@@ -0,0 +1,214 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/prediction_mask.h"
+
+#include <array>
+#include <cstdint>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr int kWedgeDirectionTypes = 16;
+
+enum kWedgeDirection : uint8_t {
+  kWedgeHorizontal,
+  kWedgeVertical,
+  kWedgeOblique27,
+  kWedgeOblique63,
+  kWedgeOblique117,
+  kWedgeOblique153,
+};
+
+const char* const kExpectedWedgeMask[] = {
+    "cea09e4bf4227efef749672283f7369b", "2763ab02b70447b2f9d5ed4796ca33bc",
+    "8d83c4315eadda824893c3e79aa866d9", "a733fd7f143c1c6141983c5f816bb3d8",
+    "9a205bfca776ccde57a8031350f2f467", "d78b964719f52f302f4454df14e45e35",
+    "bdc3972cfeb44d0acebb49b2fcb76072", "c8872571833c165be99ada1c552bfd9b",
+    "26d2541e2f8efe48e2f4a1819b3a6896", "783871179337e78e5ef41a66c0c6937c",
+    "253d21c612d732fceedcf610c4ff099c", "c868d177dc2a2378ef362fa482f601e8",
+    "782d75e143d87cc1aeb5d040c48d3c2d", "718cbecf4db45c7d596eba07bd956601",
+    "3b60b9336c2cf699172eb4a3fef18787", "afe72d4bd206f1cb27e3736c3b0068cf",
+    "7b830a1a94bad23a1df1b8d9668708d0", "d3f421ff2b81686fd421f7c02622aac1",
+    "d9ac14dff8e3c415e85e99c3ce0fbd5b", "da493727a08773a950a0375881d912f2",
+    "2f4251fd1b4636a034e22611ea1223b6", "84f84f01900b8a894b19e353605846b0",
+    "bbf5dae73300b6a6789710ffc4fc59fd", "c711941a0889fbed9b926c1eb39a5616",
+    "2fcf270613df57a57e647f37bf9a19ec", "79ed9c2f828b765edf65027f1f0847f5",
+    "e8d3e821f4e7f2f39659071da8f2cc71", "823bb09e2c28f2a81bf8a2d030e8bab6",
+    "d598fb4f70ea6b705674497994aecbfa", "3737c39f058c57650be7e720dcd87aa1",
+    "eb1d9b1d30485d9870ca9380cbdfad43", "a23d3c24f291080fcd62c0a2a2aea181",
+    "968543d91aeae3b1814a5074b6aa9e8c", "6e2444d71a4f3ddfe643e72f9c3cf6c3",
+    "3bf78413aa04830849a3d9c7bfa41a84", "ece8306f9859bcfb042b0bda8f6750b6",
+    "608b29fcedb7fa054a599945b497c78c", "d69d622016872469dfbde4e589bfd679",
+    "38a2307174c27b634323c59da3339dc6", "5e44f0fad99dbe802ffd69c7dc239d56",
+    "a0eeaf3755a724fdf6469f43cb060d75", "7bcf8035c5057619ea8660c32802d6a1",
+    "6054e1c35fe13b9269ab01d1bc0d8848", "e0ec8f7c66ebabff60f5accd3d707788",
+    "0b9fd6e1053a706af5d0cd59dc7e1992", "709648ffab1992d8522b04ca23de577a",
+    "c576e378ed264d6cb00adfd3b4e428f1", "f6f3ae5348e7141775a8a6bc2be22f80",
+    "9289722adb38fa3b2fb775648f0cc3a8", "b7e02fa00b56aeea8e6098a92eac72e1",
+    "db2f6d66ffca8352271f1e3f0116838a", "5858c567b0719daaa364fb0e6d8aa5dc",
+    "db2d300f875d2465adabf4c1322cea6f", "05c66b54c4d32e5b64a7e77e751f0c51",
+    "f2c2a5a3ce510d21ef2e62eedba85afb", "3959d2191a11e800289e21fd283b2837",
+    "cc86023d079a4c5daadce8ad0cdd176f", "e853f3c6814a653a52926488184aae5e",
+    "8568b9d7215bb8dfb1b7ce66ef38e055", "42814ac5ed652afb4734465cca9e038c",
+    "dba6b7d5e93e6a20dac9a514824ad45c", "be77e0dce733b564e96024ea23c9db43",
+    "2aa7bd75a1d8eb1000f0ef9e19aa0d1d", "226d85741e3f35493e971dd13b689ec7",
+    "9e5a0cf4416f8afeaa3ddbe686b5b7db", "18389c77b362f6b4b727b99426251159",
+    "10c5d899de999bbdf35839be3f2d5ee3", "942ae479a36fb4b4d359bebd78a92f03",
+    "f14e4dd174958e16755cd1f456b083e0", "8a036cbd0aaf1bece25a1140109f688b",
+    "2e48eade95f9fa0b7dae147e66d83e13", "4387d723350a011e26b0e91bbeb3d7c2",
+    "5470f977d859232335945efc8bb49ff1", "6780fd81cf2561300c75c930e715c7a6",
+    "9786aca6b1b9abfc3eae51404bc3cbd5", "da65c1440fa370a0237284bf30e56b0b",
+    "8e0d5d83ab3c477fd11ef143a832f7bf", "97489c7a47aa69fef091e7e6e4049a8f",
+    "28787beac9e69001c2999976742764a3", "67760c48ff5f7bc50cd92727694ba271",
+    "57c2b0b7de5de0f40fb739ed095d82a4", "7b2a663ca7da4b73f1adfc7e0ca1eff1",
+    "980869e1795efb63ca623ce2f0043fb3", "575497eb213b05bab24017cc6ea4e56a",
+    "ca3b31382439f0bdd87b61fa10c7863b", "72c65bf29afb288f4d4ff51816429aa7",
+    "1fe8929387be982993cd2309e3eeae7a", "994246e2585179e00f49537713f33796",
+    "82ae324ba01002370e918724ce452738", "fb3bcb4811b8251f0cc5ec40859617e7",
+    "a2e24b21c1d3661412e00411d719210c", "7adc2b60d7d62df1d07e3e4458a46dc2",
+    "e71c1b2f9ccb1af0868c3869dc296506", "3e33e087c7e6f724528abbc658a1b631",
+    "19b80d80f6b83eedac4bab6226865ae1", "7d9293641c4ed3b21c14964ec785cfb9",
+    "5dd0fb9700f30c25bf7b65367c8f098d", "f96b55ec2d012807c972ef4731acd73d",
+    "5fc70808c3fa5b3c511926b434bfba66", "768c3ce37acfcd4e5ba05152e5710bc9",
+    "1271a52682566ebfc01d5c239177ffd4", "52d4fc11a7507695b2548e0424be50ab",
+    "729e7d421aaaf74daa27b0ce1ca0a305", "92d2ff4a9a679cdf0ff765a2d30bced1",
+    "d160ec6f1bd864eb2ac8fabf5af7fedd", "ad323dbcb4a651e96bd5c81bc185385d",
+    "937c1b7106a2e6aef0adf2c858b4df18", "0f9ad42d1c48970f8462921ac79849ee",
+    "32ed1e1a16ddbf816f81caca7cb56c93", "e91aa6389d8255b7744aaa875ba2ceec",
+    "88f9dedf6d565b2f60b511e389cf366a", "d0428fd42ca311cd3680ff4670d4f047",
+    "b9c7eeb7c9733f0220587643952602cb", "65adf32a5e03d161a411815179078ba3",
+    "4984a4e9a5bdf732c071d5b60029daf4", "b9b65a2a9f04b59766d305221e4cda5a",
+    "7b2d372fe33d6db1fcf75820b7523ed5", "9a07593316707f8e59fe09c7647ade15",
+    "33e75e0d2aa73e3410095c2f98c27a14", "f9ddb33b16431ff9cf6ae96dd4acc792",
+    "2df1a8655b2ef23f642b11b76b20f557", "9faba399ccf555c25a33c336cdd54d94",
+    "c94404e263c2dae2e955ead645348c08", "3d16d4be87cd4467c3f7be17287940c8",
+    "99d0fdae81d61680c7a5b1df38dc98fc", "a23b402d699a00c5c349b17e77f73552",
+    "c6f76c81c4050939a6bd5d30ca00b307", "bc3d035bd6e8f55497bfc6d1f81fc8be",
+    "99b10db073e13b49bd90655f7516383b", "ddfd0e434efe076e2706c5669c788566",
+    "e1d836f814e6eca80ef530f8676e0599", "ed3e4c64e9fd1006e0016e460970a423",
+    "0282542e21fa0dea0bf48ec0a2d25b2d", "7482eb8a7bf1417a61c21d82bc7c95f9",
+    "e98e9bb3d5edf7b943d0bbf1eec9bef6", "ad4d313beecf609ff3a7d30da3e54a1d",
+    "b98f8db9fa62fb73d26415f6fa31b330", "0591b3c34bf4750f20a74eee165a54bd",
+    "3054b56fec6968255f21d40f80f5121c", "59ecf60cbb8408e042816e73446fa79c",
+    "8fa8c996209a1ddb8a00c14ca19953f8", "e20d2462bc43a1a1bfbc5efe7a905666",
+    "b5065e40d5d103e21daabcf4d5fea805", "b65aba0f8e307ef08951f1abdb7c8f62",
+    "5fbec6e57c1c651bd7be69fccb0b39a6", "9dfc362f7212d086418b0def54a7c76c",
+    "6644928e9aaac5e5d64f4a2c437c778a", "1bf63c7539ea32489bec222d5bc5305f",
+    "755ec607a5edf116d188353a96a025c3", "bdc4cc354c4f57c38d3be3dbc9380e2d",
+    "7851752b4ae36793ab6f03cd91e7ba6f", "99b9834ea2f6ea8d9168c5c1ba7fe790",
+    "75a155c83b618b28d48f5f343cdfef62", "38821c97e04d2294766699a6846fefaf",
+    "14be7f588461273862c9d9b83d2f6f0a", "8c38ce521671f0eee7e6f6349ef4f981",
+    "043347de994f2fe68c08e7c06a7f6735", "cda15ea2caccbdd8a7342a6144278578",
+    "244d586e88c9d6a9a59059a82c3b8e57", "3712928dd0dd77f027370f22d61366a0",
+    "e4f1cd4785fc331ad6e3100da4a934f3", "3181459434921b5b15b64cfd2ee734c4",
+    "2d588831e98c7178c5370421a6f2fc60", "135cf6a67fc1b51dbcf9fcddb3ae1237",
+    "d701da4e1a890a37bb0e9af4a2f0b048", "02138b5a4882181f248945c3a8262050",
+    "7fbd4d06965b1d152d6c037b0302f307", "7917a20573da241868689ed49c0d5972",
+    "ffdd4257d91fe00e61de4d2668f1ee07", "72999b6d3bf1ee189e9269a27105991f",
+    "1b63d7f25388c9af4adac60d46b7a8ca", "e3ce0977224197ade58aa979f3206d68",
+    "73178ffd388b46891fc4a0440686b554", "f1f99faf52cea98c825470c6edd1d973",
+    "e6fae5d5682862ec3377b714b6b69825", "a4f96cca8da155204b0cc4258b068d3c",
+    "75c7674c2356325dcb14c222266c46f8", "932b23521c9d9d06096879a665a14e28",
+    "8ed48a84a99b4a5bf2ec8a7a2c1f1c79", "4f6f0214857a92ad92eca1c33a762424",
+    "34865190c3e91200a0609a6e770ebc5c", "e793f1f2e46876b1e417da5d59475fda",
+    "e83cd9a228941a152f6878aa939e1290", "d6f5cd74ba386bd98282e1fcb0528dbd",
+    "131b55ec66ffe76f9088f7b35d38c0dd", "2d0ae8ee059cbd8c7816e3c862efdf37",
+    "65baadd2cb85ffbc6480bf8c1f128d1a", "2b8e8af333c464b4213bbd9185a9b751",
+    "951fd5faed77a1ae9bf5ef8f30bd65c3", "41d38d40dfe9da2b9ff2146711bf6ab5",
+    "7430bde28aed5a9429db54ea663a5e26", "46576d59a13756c494793ad4b3a663e5",
+    "21802d0db30caa44cbdba2ac84cc49b5", "591cad82ae106d9e9670acd5b60e4548",
+    "c0484c58c6c009939e7f3ec0c1aa8e2d", "6405c55d0a1830cfdd37950bfd65fd6f",
+    "3bd74c067d2ba027fc004e9bf62254db", "6e920e6dbdbe55a97ff2bf3dfb38a3e0",
+    "e2ed20f89da293516b14be766a624299", "0a613ee53ec38cad995faa17a24fcb8f",
+    "0de937145c030d766c3f9fff09d7e39c", "4a560325b804fcb6643866e971ade8e8",
+    "be82c41d3a0f8bd4032c3e5e45b453da", "b27219f02db167bf5a416831b908b031",
+    "7cf5437e25d362bc373dd53d8fd78186", "39c801e28cc08150c2016083113d1a03",
+    "785a21219d9c42a7c5bd417f365535a3", "008c79298a87837bcb504c4dc39ca628",
+    "af24d1d6f4d3ee94f2af52471a64ca1f", "cd82218aae9815c106336aec7ce18833",
+    "9f405c66d4ce7533213c4ca82feaf252", "7ceda4ea6ddeccd04dbf6d3237fe956a",
+    "ae21b52869b85a64fa4e3a85a2a8bb8d", "a004927cdbf48e0dafcccfb6066cdd0c",
+    "949337a963a8a5c0f46cf774b078a7cd", "24f58b8db17d02f66d04d22ca6c5e026",
+    "2b1315a2e7c5d5309a7621651e741616", "5b317ef820e6c8e7ea7a7d7022e8349d",
+    "debd504650d35d9deca4c2461094949f", "19d0ca33e5b3a0afff1f39f0f42238e0",
+    "df1c6c7582bfa5ceb147a8dd253cfa43", "176647077c5e2d985b3807134aac118f",
+    "dd2850172602688eaaa768f705c1ba67", "6ba1a3929ae9725fc688b8189b16314f",
+    "639189abb754dfa6be3c813ee8342954", "d5d1b8bff370f280fba13827d6bdf0fb",
+    "4b0ad4ea387a952724cab42730f712d2", "8c9c1f09946b61315e9a45c7e39f1992",
+    "50ef75c2b7a17f972586ce053eb62d24", "d5922dd01d8d02ca00ab9648a3db343f",
+    "091f517b18f4438ea9c581b7471f2fc0", "fede855bfb936caaa8fb4a434adac1d3",
+    "081b612f810f38c5ff6dc1cd03bf2eb6", "bd10e764eaf7d7e0ec89de96423d0afe",
+    "3e64cb1355e05b0a4b0237fae3f33bb2", "7cb92e0ecc0dd06d0a5d248efba48630",
+    "ec875f2e155a2e124ef52bf35e9a876c", "15529c83eae41bfa804f2c386f480e90",
+    "ee0e59567874155fb54de63fc901ded7", "4ad160b0d0f5166f9cddf7235725406e",
+    "176b64b3883c33e2aa251159983ccaa1", "d9cca01946d2a47c0114b1f49e4d688f",
+    "73d706a13afa279d9c716b3ba3a2ed68", "dea5a7f010d2f1385fe2b7d1d36aafb0",
+    "b5432fbc22d2f96c1230cc33178da09e", "8b0e7399ce98b68de4048411ab649468",
+    "3d52c986a5a5852a4620fbb38259a109", "eb61882738fefdd105094d4c104cf8b0",
+    "24fbc0d3ee28e937cfa1a3fbbc4e8214", "c69eb0687e477c27ac0d4c5fe54bbe8b",
+    "00a4f498f05b2b348252927ecc82c8a3", "c76471a61250be52e8d5933e582b1e19",
+    "22ebb8812dd795fdc14f20a7f9f89844", "f7c7d5c04bc234545726f4b116b623ec",
+    "9fc323d6619af0101edfacb4e9c2b647", "902d7888215d6aac1cf41f1fb6a916d8",
+    "5817d80a0504a5b08627502aeece4f38", "a1afa4b4065c143bc4857e364cec7f3d",
+    "506d5a6ff434411ea893bb2dc021aa25", "31cd3ca39015ccee1e217e1c83fff2a0",
+    "eb1ed4ef292c7d8fead1f113c9fd998f", "35f3abf3a056b778e3d7885f8df6c07a",
+    "299d71ee557382f5e64f26f1a8e4e156", "12f8c591a4e257bcc26b385424cd8d47",
+    "0b273b03d817af587c8fb23de71f346d", "1d7592fe89c661e9f61d215d235aa2ee",
+    "331dc544956ee14064ab432c85d52828", "a0a4ccbe1c442717ad40b7d40ed81a40",
+    "45009d915bf1d4ab855b5b670d314839", "641dfe93841aaa18888cebb17b8566eb",
+    "2b177c880ce0c2b4e891abc1dc23dfc2", "23984491f7d6c206fb8babafc9aacfdb",
+    "5841b93edb22c702035e31b26c58a728", "9852506766cb47f48783640d14753089",
+    "8a43698d32f63b1e7191482e4b274fc3", "7bdef02623beae507a651ad398422876",
+    "b105138645ad27657a08a3a8e8871a7e", "913e40ebbf1b983ca4956b85364b9459",
+    "5776f97b4f0cfa435a99d5d90822922d", "a0ae92a24c2b20039d996ee2a7d8b107",
+    "a925cc792412e2a7abe89367c9fe28b1", "778183eab5c9e0ee559d828d8347a21c",
+    "c4b4777355a4c8e8858faec37ba23eec", "4cdd41c3648e8d05c3e8f58d08385f8b",
+    "7c1246737874f984feb1b5827a1f95db", "c75d766ff5af8db39d400962d5aba0b4",
+    "964f010f5aa6748461ca5573b013091d", "b003f3eab3b118e5a8a85c1873b3bb55"};
+
+TEST(WedgePredictionMaskTest, GenerateWedgeMask) {
+  WedgeMaskArray wedge_masks;
+  ASSERT_TRUE(GenerateWedgeMask(&wedge_masks));
+
+  // Check wedge masks.
+  int block_size_index = 0;
+  int index = 0;
+  for (int block_size = kBlock8x8; block_size < kMaxBlockSizes; ++block_size) {
+    const int width = kBlockWidthPixels[block_size];
+    const int height = kBlockHeightPixels[block_size];
+    if (width < 8 || height < 8 || width > 32 || height > 32) continue;
+
+    for (int flip_sign = 0; flip_sign <= 1; ++flip_sign) {
+      for (int direction = 0; direction < kWedgeDirectionTypes; ++direction) {
+        uint8_t* const block_wedge_mask =
+            wedge_masks[block_size_index][flip_sign][direction][0];
+        const std::string digest =
+            test_utils::GetMd5Sum(block_wedge_mask, width * height);
+        EXPECT_STREQ(digest.c_str(), kExpectedWedgeMask[index]);
+        index++;
+      }
+    }
+    block_size_index++;
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/quantizer_test.cc b/src/quantizer_test.cc
new file mode 100644
index 0000000..0c27027
--- /dev/null
+++ b/src/quantizer_test.cc
@@ -0,0 +1,220 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/quantizer.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "src/obu_parser.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(QuantizerTest, GetQIndex) {
+  const int kBaseQIndex = 40;
+  const int kDelta = 10;
+  const int kOutOfRangeIndex = 200;
+  Segmentation segmentation = {};
+
+  EXPECT_EQ(GetQIndex(segmentation, 0, kBaseQIndex), kBaseQIndex);
+  EXPECT_EQ(GetQIndex(segmentation, kOutOfRangeIndex, kBaseQIndex),
+            kBaseQIndex);
+
+  segmentation.enabled = true;
+  EXPECT_EQ(GetQIndex(segmentation, 0, kBaseQIndex), kBaseQIndex);
+  EXPECT_EQ(GetQIndex(segmentation, kOutOfRangeIndex, kBaseQIndex),
+            kBaseQIndex);
+
+  segmentation.feature_enabled[1][kSegmentFeatureQuantizer] = true;
+  segmentation.feature_data[1][kSegmentFeatureQuantizer] = kDelta;
+  EXPECT_EQ(GetQIndex(segmentation, 1, kBaseQIndex), kBaseQIndex + kDelta);
+  EXPECT_EQ(GetQIndex(segmentation, kOutOfRangeIndex, kBaseQIndex),
+            kBaseQIndex);
+
+  segmentation.enabled = false;
+  EXPECT_EQ(GetQIndex(segmentation, 1, kBaseQIndex), kBaseQIndex);
+  EXPECT_EQ(GetQIndex(segmentation, kOutOfRangeIndex, kBaseQIndex),
+            kBaseQIndex);
+}
+
+TEST(QuantizerTest, GetDcValue) {
+  QuantizerParameters params = {};
+  params.delta_dc[kPlaneY] = 1;
+  params.delta_dc[kPlaneU] = 2;
+  params.delta_dc[kPlaneV] = 3;
+
+  // Test lookups of Dc_Qlookup[0][0], Dc_Qlookup[0][11], Dc_Qlookup[0][12],
+  // and Dc_Qlookup[0][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(8, &params);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 10), 16);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 11), 17);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 254), 1336);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 255), 1336);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 9), 16);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 10), 17);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 253), 1336);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 254), 1336);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -4), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 8), 16);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 9), 17);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 252), 1336);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 253), 1336);
+  }
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+  // Test lookups of Dc_Qlookup[1][0], Dc_Qlookup[1][11], Dc_Qlookup[1][12],
+  // and Dc_Qlookup[1][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(10, &params);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 10), 34);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 11), 37);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 254), 5347);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 255), 5347);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 9), 34);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 10), 37);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 253), 5347);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 254), 5347);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -4), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 8), 34);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 9), 37);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 254), 5347);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 253), 5347);
+  }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+  // Test lookups of Dc_Qlookup[2][0], Dc_Qlookup[2][11], Dc_Qlookup[2][12],
+  // and Dc_Qlookup[2][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(12, &params);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 10), 103);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 11), 115);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 254), 21387);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneY, 255), 21387);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 9), 103);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 10), 115);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 253), 21387);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneU, 254), 21387);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -4), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 8), 103);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 9), 115);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 254), 21387);
+    EXPECT_EQ(quantizer.GetDcValue(kPlaneV, 253), 21387);
+  }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+}
+
+TEST(QuantizerTest, GetAcValue) {
+  QuantizerParameters params = {};
+  params.delta_ac[kPlaneU] = 1;
+  params.delta_ac[kPlaneV] = 2;
+
+  // Test lookups of Ac_Qlookup[0][0], Ac_Qlookup[0][11], Ac_Qlookup[0][12],
+  // and Ac_Qlookup[0][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(8, &params);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 0), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 11), 18);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 12), 19);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 255), 1828);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 256), 1828);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 10), 18);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 11), 19);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 254), 1828);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 255), 1828);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 9), 18);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 10), 19);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 253), 1828);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 254), 1828);
+  }
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+  // Test lookups of Ac_Qlookup[1][0], Ac_Qlookup[1][11], Ac_Qlookup[1][12],
+  // and Ac_Qlookup[1][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(10, &params);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 0), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 11), 37);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 12), 40);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 255), 7312);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 256), 7312);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 10), 37);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 11), 40);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 254), 7312);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 255), 7312);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 9), 37);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 10), 40);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 253), 7312);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 254), 7312);
+  }
+#endif  // LIBGAV1_MAX_BITDEPTH >= 10
+
+#if LIBGAV1_MAX_BITDEPTH == 12
+  // Test lookups of Ac_Qlookup[1][0], Ac_Qlookup[1][11], Ac_Qlookup[1][12],
+  // and Ac_Qlookup[1][255] in the spec, including the clipping of qindex.
+  {
+    Quantizer quantizer(12, &params);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 0), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 11), 112);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 12), 126);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 255), 29247);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneY, 256), 29247);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, -1), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 10), 112);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 11), 126);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 254), 29247);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneU, 255), 29247);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -3), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, -2), 4);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 9), 112);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 10), 126);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 253), 29247);
+    EXPECT_EQ(quantizer.GetAcValue(kPlaneV, 254), 29247);
+  }
+#endif  // LIBGAV1_MAX_BITDEPTH == 12
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/reconstruction_test.cc b/src/reconstruction_test.cc
new file mode 100644
index 0000000..fd780b3
--- /dev/null
+++ b/src/reconstruction_test.cc
@@ -0,0 +1,294 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/reconstruction.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include "absl/strings/match.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "src/dsp/constants.h"
+#include "src/dsp/dsp.h"
+#include "src/dsp/inverse_transform.h"
+#include "src/utils/array_2d.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/cpu.h"
+#include "src/utils/memory.h"
+#include "tests/block_utils.h"
+#include "tests/utils.h"
+
+namespace libgav1 {
+namespace {
+
+// Import the scan tables in the anonymous namespace.
+#include "src/scan_tables.inc"
+
+constexpr int kTestTransformSize = 4;
+constexpr int8_t kTestBitdepth = 8;
+
+using testing::ElementsAreArray;
+
+// The 'int' parameter is unused but required to allow for instantiations of C,
+// NEON, etc.
+class ReconstructionTest : public testing::TestWithParam<int> {
+ public:
+  ReconstructionTest() = default;
+  ReconstructionTest(const ReconstructionTest&) = delete;
+  ReconstructionTest& operator=(const ReconstructionTest&) = delete;
+  ~ReconstructionTest() override = default;
+
+ protected:
+  void SetUp() override {
+    test_utils::ResetDspTable(kTestBitdepth);
+    dsp::InverseTransformInit_C();
+    dsp_ = dsp::GetDspTable(kTestBitdepth);
+    ASSERT_NE(dsp_, nullptr);
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    if (test_info->value_param() != nullptr) {
+      const char* const test_case = test_info->test_suite_name();
+      if (absl::StartsWith(test_case, "C/")) {
+      } else if (absl::StartsWith(test_case, "SSE41/")) {
+        if ((GetCpuInfo() & kSSE4_1) != 0) {
+          dsp::InverseTransformInit_SSE4_1();
+        }
+      } else if (absl::StartsWith(test_case, "NEON/")) {
+        dsp::InverseTransformInit_NEON();
+      } else {
+        FAIL() << "Unrecognized architecture prefix in test case name: "
+               << test_case;
+      }
+    }
+    InitBuffers();
+  }
+
+  void InitBuffers(int width = kTestTransformSize,
+                   int height = kTestTransformSize) {
+    const int size = width * height;
+    buffer_.clear();
+    buffer_.resize(size);
+    residual_buffer_.clear();
+    residual_buffer_.resize(size);
+    for (int i = 0; i < size; ++i) {
+      buffer_[i] = residual_buffer_[i] = i % 256;
+    }
+    frame_buffer_.Reset(height, width, buffer_.data());
+  }
+
+  template <int bitdepth>
+  void TestWht();
+
+  std::vector<uint8_t> buffer_;
+  std::vector<int16_t> residual_buffer_;
+  // |frame_buffer_| is just a 2D array view into the |buffer_|.
+  Array2DView<uint8_t> frame_buffer_;
+  const dsp::Dsp* dsp_;
+};
+
+template <int bitdepth>
+void ReconstructionTest::TestWht() {
+  static_assert(bitdepth == kBitdepth8 || bitdepth == kBitdepth10, "");
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dWht][dsp::kTransform1dSize4]) {
+    if (transform == nullptr) {
+      GTEST_SKIP() << "No function available for dsp::kTransform1dWht";
+    }
+  }
+  constexpr int max = 16 << bitdepth;
+  constexpr int min = -max;
+  static constexpr int16_t residual_inputs[][16]{
+      {64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, max - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, min - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+      // Note these are unrealistic inputs, but serve to test each position in
+      // the array and match extremes in some commercial test vectors.
+      {max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+       max, max},
+      {min, min, min, min, min, min, min, min, min, min, min, min, min, min,
+       min, min}};
+  // Before the Reconstruct() call, the frame buffer is filled with all 127.
+  // After the Reconstruct() call, the frame buffer is expected to have the
+  // following values.
+  static constexpr uint8_t frame_outputs[][16]{
+      {131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+       131, 131},
+      {132, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+       131, 131},
+      {255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255},
+      {0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0},
+      {255, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+       127, 127},
+      {0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+       127},
+  };
+
+  const TransformSize tx_size = kTransformSize4x4;
+  const TransformType tx_type = kTransformTypeDctDct;
+  const int tx_width = kTransformWidth[tx_size];
+  const int tx_height = kTransformHeight[tx_size];
+  const uint16_t* const scan = kScan[GetTransformClass(tx_type)][tx_size];
+
+  InitBuffers(tx_width, tx_height);
+
+  const int num_tests = sizeof(residual_inputs) / sizeof(residual_inputs[0]);
+  for (int i = 0; i < num_tests; ++i) {
+    int16_t eob;  // Also known as non_zero_coeff_count.
+    for (eob = 15; eob >= 0; --eob) {
+      if (residual_inputs[i][scan[eob]] != 0) break;
+    }
+    ++eob;
+    memcpy(residual_buffer_.data(), residual_inputs[i],
+           sizeof(residual_inputs[i]));
+    memset(buffer_.data(), 127, sizeof(frame_outputs[i]));
+    Reconstruct(*dsp_, tx_type, tx_size, /*lossless=*/true,
+                residual_buffer_.data(), 0, 0, &frame_buffer_, eob);
+
+    EXPECT_TRUE(test_utils::CompareBlocks(buffer_.data(), frame_outputs[i],
+                                          tx_width, tx_height, tx_width,
+                                          tx_width, false, true))
+        << "Mismatch WHT test case " << i;
+  }
+}
+
+TEST_P(ReconstructionTest, ReconstructionSimple) {
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dIdentity]
+                               [dsp::kTransform1dSize4]) {
+    if (transform == nullptr) GTEST_SKIP();
+  }
+  Reconstruct(*dsp_, kTransformTypeIdentityIdentity, kTransformSize4x4, false,
+              residual_buffer_.data(), 0, 0, &frame_buffer_, 16);
+  // clang-format off
+  static constexpr uint8_t expected_output_buffer[] = {
+      0, 1, 2, 3,
+      5, 6, 7, 8,
+      9, 10, 11, 12,
+      14, 15, 16, 17
+  };
+  // clang-format on
+  EXPECT_THAT(buffer_, ElementsAreArray(expected_output_buffer));
+}
+
+TEST_P(ReconstructionTest, ReconstructionFlipY) {
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dIdentity]
+                               [dsp::kTransform1dSize4]) {
+    if (transform == nullptr) GTEST_SKIP();
+  }
+  Reconstruct(*dsp_, kTransformTypeIdentityFlipadst, kTransformSize4x4, false,
+              residual_buffer_.data(), 0, 0, &frame_buffer_, 16);
+  // clang-format off
+  static constexpr uint8_t expected_buffer[] = {
+      0, 1, 2, 3,
+      4, 5, 6, 7,
+      7, 8, 9, 10,
+      14, 15, 16, 17
+  };
+  // clang-format on
+  EXPECT_THAT(buffer_, ElementsAreArray(expected_buffer));
+}
+
+TEST_P(ReconstructionTest, ReconstructionFlipX) {
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dIdentity]
+                               [dsp::kTransform1dSize4]) {
+    if (transform == nullptr) GTEST_SKIP();
+  }
+  Reconstruct(*dsp_, kTransformTypeFlipadstIdentity, kTransformSize4x4, false,
+              residual_buffer_.data(), 0, 0, &frame_buffer_, 16);
+  // clang-format off
+  static constexpr uint8_t expected_buffer[] = {
+      0, 1, 2, 3,
+      4, 5, 6, 8,
+      8, 10, 10, 13,
+      12, 14, 14, 18
+  };
+  // clang-format on
+  EXPECT_THAT(buffer_, ElementsAreArray(expected_buffer));
+}
+
+TEST_P(ReconstructionTest, ReconstructionFlipXAndFlipY) {
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dIdentity]
+                               [dsp::kTransform1dSize4]) {
+    if (transform == nullptr) GTEST_SKIP();
+  }
+  Reconstruct(*dsp_, kTransformTypeFlipadstFlipadst, kTransformSize4x4, false,
+              residual_buffer_.data(), 0, 0, &frame_buffer_, 16);
+  // clang-format off
+  static constexpr uint8_t expected_buffer[] = {
+      0, 1, 2, 3,
+      4, 5, 6, 8,
+      8, 8, 10, 9,
+      12, 14, 14, 19
+  };
+  // clang-format on
+  EXPECT_THAT(buffer_, ElementsAreArray(expected_buffer));
+}
+
+TEST_P(ReconstructionTest, ReconstructionNonZeroStart) {
+  uint8_t buffer[64] = {};
+  Array2DView<uint8_t> frame_buffer(8, 8, buffer);
+  int k = 0;
+  for (int i = 0; i < kTestTransformSize; ++i) {
+    for (int j = 0; j < kTestTransformSize; ++j) {
+      frame_buffer[i + 4][j + 4] = k++;
+    }
+  }
+  for (const auto transform :
+       dsp_->inverse_transforms[dsp::kTransform1dIdentity]
+                               [dsp::kTransform1dSize4]) {
+    if (transform == nullptr) GTEST_SKIP();
+  }
+  Reconstruct(*dsp_, kTransformTypeIdentityIdentity, kTransformSize4x4, false,
+              residual_buffer_.data(), 4, 4, &frame_buffer, 64);
+  // clang-format off
+  static constexpr uint8_t expected_buffer[] = {
+      0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 0, 0, 0,
+      0, 0, 0, 0, 0, 1, 2, 3,
+      0, 0, 0, 0, 5, 6, 7, 8,
+      0, 0, 0, 0, 9, 10, 11, 12,
+      0, 0, 0, 0, 14, 15, 16, 17
+  };
+  // clang-format on
+  EXPECT_THAT(buffer, ElementsAreArray(expected_buffer));
+}
+
+TEST_P(ReconstructionTest, Wht8bit) { TestWht<kBitdepth8>(); }
+
+#if LIBGAV1_MAX_BITDEPTH >= 10
+TEST_P(ReconstructionTest, Wht10bit) { TestWht<kBitdepth10>(); }
+#endif
+
+INSTANTIATE_TEST_SUITE_P(C, ReconstructionTest, testing::Values(0));
+
+#if LIBGAV1_ENABLE_SSE4_1
+INSTANTIATE_TEST_SUITE_P(SSE41, ReconstructionTest, testing::Values(0));
+#endif
+
+#if LIBGAV1_ENABLE_NEON
+INSTANTIATE_TEST_SUITE_P(NEON, ReconstructionTest, testing::Values(0));
+#endif
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/residual_buffer_pool_test.cc b/src/residual_buffer_pool_test.cc
new file mode 100644
index 0000000..84bc747
--- /dev/null
+++ b/src/residual_buffer_pool_test.cc
@@ -0,0 +1,201 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/residual_buffer_pool.h"
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/utils/constants.h"
+#include "src/utils/queue.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(ResidualBufferTest, TestUsage) {
+  ResidualBufferPool pool(true, 1, 1, sizeof(int16_t));
+  EXPECT_EQ(pool.Size(), 0);
+  // Get one buffer.
+  std::unique_ptr<ResidualBuffer> buffer1 = pool.Get();
+  uint8_t* const buffer1_ptr = buffer1->buffer();
+  ASSERT_NE(buffer1_ptr, nullptr);
+  // Get another buffer (while holding on to the first one).
+  std::unique_ptr<ResidualBuffer> buffer2 = pool.Get();
+  uint8_t* const buffer2_ptr = buffer2->buffer();
+  ASSERT_NE(buffer2_ptr, nullptr);
+  EXPECT_NE(buffer1_ptr, buffer2_ptr);
+  // Return the second buffer.
+  pool.Release(std::move(buffer2));
+  EXPECT_EQ(pool.Size(), 1);
+  // Get another buffer (this one should be the same as the buffer2).
+  std::unique_ptr<ResidualBuffer> buffer3 = pool.Get();
+  uint8_t* const buffer3_ptr = buffer3->buffer();
+  ASSERT_NE(buffer3_ptr, nullptr);
+  EXPECT_EQ(buffer3_ptr, buffer2_ptr);
+  EXPECT_EQ(pool.Size(), 0);
+  // Get another buffer (this one will be a new buffer).
+  std::unique_ptr<ResidualBuffer> buffer4 = pool.Get();
+  uint8_t* const buffer4_ptr = buffer4->buffer();
+  ASSERT_NE(buffer4_ptr, nullptr);
+  EXPECT_NE(buffer4_ptr, buffer1_ptr);
+  EXPECT_NE(buffer4_ptr, buffer3_ptr);
+  EXPECT_EQ(pool.Size(), 0);
+  // Return all the buffers.
+  pool.Release(std::move(buffer1));
+  EXPECT_EQ(pool.Size(), 1);
+  pool.Release(std::move(buffer3));
+  EXPECT_EQ(pool.Size(), 2);
+  pool.Release(std::move(buffer4));
+  EXPECT_EQ(pool.Size(), 3);
+  // Reset the buffer with same parameters.
+  pool.Reset(true, 1, 1, sizeof(int16_t));
+  EXPECT_EQ(pool.Size(), 3);
+  // Reset the buffer size with different parameters.
+  pool.Reset(true, 0, 1, sizeof(int32_t));
+  // The existing buffers should now have been invalidated.
+  EXPECT_EQ(pool.Size(), 0);
+  // Get and return a buffer.
+  std::unique_ptr<ResidualBuffer> buffer5 = pool.Get();
+  uint8_t* const buffer5_ptr = buffer5->buffer();
+  ASSERT_NE(buffer5_ptr, nullptr);
+  pool.Release(std::move(buffer5));
+  EXPECT_EQ(pool.Size(), 1);
+  // Reset the buffer with different value for use128x128_superblock.
+  pool.Reset(false, 0, 1, sizeof(int32_t));
+  // The existing buffers should now have been invalidated.
+  EXPECT_EQ(pool.Size(), 0);
+}
+
+TEST(ResidualBufferTest, TestQueue) {
+  ResidualBufferPool pool(true, 1, 1, sizeof(int16_t));
+  EXPECT_EQ(pool.Size(), 0);
+  // Get one buffer.
+  std::unique_ptr<ResidualBuffer> buffer1 = pool.Get();
+  uint8_t* const buffer1_ptr = buffer1->buffer();
+  ASSERT_NE(buffer1_ptr, nullptr);
+  auto* queue1 = buffer1->transform_parameters();
+  queue1->Push(TransformParameters(kTransformTypeAdstAdst, 10));
+  EXPECT_EQ(queue1->Size(), 1);
+  EXPECT_EQ(queue1->Front().type, kTransformTypeAdstAdst);
+  EXPECT_EQ(queue1->Front().non_zero_coeff_count, 10);
+  queue1->Push(TransformParameters(kTransformTypeDctDct, 20));
+  EXPECT_EQ(queue1->Size(), 2);
+  EXPECT_EQ(queue1->Front().type, kTransformTypeAdstAdst);
+  EXPECT_EQ(queue1->Front().non_zero_coeff_count, 10);
+  queue1->Pop();
+  EXPECT_EQ(queue1->Size(), 1);
+  EXPECT_EQ(queue1->Front().type, kTransformTypeDctDct);
+  EXPECT_EQ(queue1->Front().non_zero_coeff_count, 20);
+  // Return the buffer.
+  pool.Release(std::move(buffer1));
+  EXPECT_EQ(pool.Size(), 1);
+  // Get another buffer (should be the same as buffer1).
+  std::unique_ptr<ResidualBuffer> buffer2 = pool.Get();
+  uint8_t* const buffer2_ptr = buffer2->buffer();
+  ASSERT_NE(buffer2_ptr, nullptr);
+  EXPECT_EQ(buffer1_ptr, buffer2_ptr);
+  // Releasing the buffer should've cleared the queue.
+  EXPECT_EQ(buffer2->transform_parameters()->Size(), 0);
+}
+
+TEST(ResidualBufferTest, TestStackPushPop) {
+  ResidualBufferStack buffers;
+  EXPECT_EQ(buffers.Size(), 0);
+  EXPECT_EQ(buffers.Pop(), nullptr);
+
+  std::unique_ptr<ResidualBuffer> buffer0 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer0_ptr = buffer0.get();
+  EXPECT_NE(buffer0_ptr, nullptr);
+  std::unique_ptr<ResidualBuffer> buffer1 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer1_ptr = buffer1.get();
+  EXPECT_NE(buffer1_ptr, nullptr);
+  std::unique_ptr<ResidualBuffer> buffer2 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer2_ptr = buffer2.get();
+  EXPECT_NE(buffer2_ptr, nullptr);
+
+  // Push two buffers onto the stack.
+  buffers.Push(std::move(buffer0));
+  EXPECT_EQ(buffers.Size(), 1);
+  buffers.Push(std::move(buffer1));
+  EXPECT_EQ(buffers.Size(), 2);
+
+  // Pop one buffer off the stack.
+  std::unique_ptr<ResidualBuffer> top = buffers.Pop();
+  EXPECT_EQ(buffers.Size(), 1);
+  EXPECT_EQ(top.get(), buffer1_ptr);
+
+  // Push one buffer onto the stack.
+  buffers.Push(std::move(buffer2));
+  EXPECT_EQ(buffers.Size(), 2);
+
+  // Pop two buffers off the stack
+  top = buffers.Pop();
+  EXPECT_EQ(buffers.Size(), 1);
+  EXPECT_EQ(top.get(), buffer2_ptr);
+  top = buffers.Pop();
+  EXPECT_EQ(buffers.Size(), 0);
+  EXPECT_EQ(top.get(), buffer0_ptr);
+
+  // Try to pop a buffer off an empty stack.
+  top = buffers.Pop();
+  EXPECT_EQ(buffers.Size(), 0);
+  EXPECT_EQ(top, nullptr);
+}
+
+TEST(ResidualBufferTest, TestStackSwap) {
+  ResidualBufferStack buffers;
+  EXPECT_EQ(buffers.Size(), 0);
+  EXPECT_EQ(buffers.Pop(), nullptr);
+
+  std::unique_ptr<ResidualBuffer> buffer0 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer0_ptr = buffer0.get();
+  EXPECT_NE(buffer0_ptr, nullptr);
+  std::unique_ptr<ResidualBuffer> buffer1 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer1_ptr = buffer1.get();
+  EXPECT_NE(buffer1_ptr, nullptr);
+  std::unique_ptr<ResidualBuffer> buffer2 = ResidualBuffer::Create(128, 128);
+  ResidualBuffer* const buffer2_ptr = buffer2.get();
+  EXPECT_NE(buffer2_ptr, nullptr);
+
+  // Push three buffers onto the stack.
+  buffers.Push(std::move(buffer0));
+  EXPECT_EQ(buffers.Size(), 1);
+  buffers.Push(std::move(buffer1));
+  EXPECT_EQ(buffers.Size(), 2);
+  buffers.Push(std::move(buffer2));
+  EXPECT_EQ(buffers.Size(), 3);
+
+  // Swap the contents of the stacks.
+  ResidualBufferStack swapped;
+  swapped.Swap(&buffers);
+  EXPECT_EQ(buffers.Size(), 0);
+  EXPECT_EQ(swapped.Size(), 3);
+
+  // Pop three buffers off the swapped stack.
+  std::unique_ptr<ResidualBuffer> top = swapped.Pop();
+  EXPECT_EQ(swapped.Size(), 2);
+  EXPECT_EQ(top.get(), buffer2_ptr);
+  top = swapped.Pop();
+  EXPECT_EQ(swapped.Size(), 1);
+  EXPECT_EQ(top.get(), buffer1_ptr);
+  top = swapped.Pop();
+  EXPECT_EQ(swapped.Size(), 0);
+  EXPECT_EQ(top.get(), buffer0_ptr);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/scan_test.cc b/src/scan_test.cc
new file mode 100644
index 0000000..065ca03
--- /dev/null
+++ b/src/scan_test.cc
@@ -0,0 +1,85 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <algorithm>
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+
+namespace libgav1 {
+namespace {
+
+// Import all the constants in the anonymous namespace.
+#include "src/scan_tables.inc"
+
+class ScanOrderTest
+    : public testing::TestWithParam<std::tuple<TransformClass, TransformSize>> {
+ public:
+  ScanOrderTest() = default;
+  ScanOrderTest(const ScanOrderTest&) = delete;
+  ScanOrderTest& operator=(const ScanOrderTest&) = delete;
+  ~ScanOrderTest() override = default;
+
+ protected:
+  TransformClass tx_class_ = std::get<0>(GetParam());
+  TransformSize tx_size_ = std::get<1>(GetParam());
+};
+
+TEST_P(ScanOrderTest, AllIndicesAreScannedExactlyOnce) {
+  const int tx_width = kTransformWidth[tx_size_];
+  const int tx_height = kTransformHeight[tx_size_];
+  int num_indices;
+  if (tx_class_ == kTransformClass2D || std::max(tx_width, tx_height) == 64) {
+    const int clamped_tx_width = std::min(32, tx_width);
+    const int clamped_tx_height = std::min(32, tx_height);
+    num_indices = clamped_tx_width * clamped_tx_height;
+  } else {
+    num_indices =
+        (std::max(tx_width, tx_height) > 16) ? 64 : tx_width * tx_height;
+  }
+  const uint16_t* const scan = kScan[tx_class_][tx_size_];
+  ASSERT_NE(scan, nullptr);
+  // Ensure that all the indices are scanned exactly once.
+  std::vector<int> scanned;
+  scanned.resize(num_indices);
+  for (int i = 0; i < num_indices; ++i) {
+    scanned[scan[i]]++;
+  }
+  EXPECT_THAT(scanned, testing::Each(1));
+}
+
+constexpr TransformClass kTestTransformClasses[] = {
+    kTransformClass2D, kTransformClassVertical, kTransformClassHorizontal};
+
+constexpr TransformSize kTestTransformSizes[] = {
+    kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
+    kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
+    kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
+    kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
+    kTransformSize32x8,  kTransformSize32x16, kTransformSize32x32,
+    kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
+    kTransformSize64x64};
+
+INSTANTIATE_TEST_SUITE_P(
+    C, ScanOrderTest,
+    testing::Combine(testing::ValuesIn(kTestTransformClasses),
+                     testing::ValuesIn(kTestTransformSizes)));
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/symbol_decoder_context_test.cc b/src/symbol_decoder_context_test.cc
new file mode 100644
index 0000000..4a0de86
--- /dev/null
+++ b/src/symbol_decoder_context_test.cc
@@ -0,0 +1,264 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/symbol_decoder_context.h"
+
+#include <cstdint>
+#include <cstring>
+
+#include "gtest/gtest.h"
+#include "src/utils/constants.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(SymbolDecoderContextTest, ResetIntraFrameYModeCdf) {
+  // Note these are zero-initialized separately to avoid differences in padding
+  // values added to tables for alignment purposes when comparing the contexts
+  // with memcmp().
+  libgav1::SymbolDecoderContext gold_context = {};
+  libgav1::SymbolDecoderContext context = {};
+  gold_context.Initialize(0);
+  context.Initialize(0);
+  EXPECT_EQ(memcmp(&gold_context, &context, sizeof(gold_context)), 0);
+  EXPECT_EQ(context.intra_frame_y_mode_cdf[0][0][0], 32768 - 15588);
+  EXPECT_EQ(context.intra_frame_y_mode_cdf[0][0][1], 32768 - 17027);
+  ++context.intra_frame_y_mode_cdf[0][0][0];
+  --context.intra_frame_y_mode_cdf[0][0][1];
+  EXPECT_NE(memcmp(&gold_context, &context, sizeof(gold_context)), 0);
+  context.ResetIntraFrameYModeCdf();
+  EXPECT_EQ(memcmp(&gold_context, &context, sizeof(gold_context)), 0);
+}
+
+void ResetAndVerifyCounters(libgav1::SymbolDecoderContext* const context) {
+  libgav1::SymbolDecoderContext gold_context = {};
+  gold_context.Initialize(0);
+  EXPECT_NE(memcmp(&gold_context, context, sizeof(gold_context)), 0);
+  context->ResetCounters();
+  EXPECT_EQ(memcmp(&gold_context, context, sizeof(gold_context)), 0);
+}
+
+TEST(SymbolDecoderContextTest, ResetCounters1d) {
+  libgav1::SymbolDecoderContext context = {};
+  context.Initialize(0);
+  int value = 0;
+  context.delta_q_cdf[libgav1::kDeltaSymbolCount] = ++value;
+  context.delta_lf_cdf[libgav1::kDeltaSymbolCount] = ++value;
+  context.intra_block_copy_cdf[libgav1::kBooleanSymbolCount] = ++value;
+  context.cfl_alpha_signs_cdf[libgav1::kCflAlphaSignsSymbolCount] = ++value;
+  context.filter_intra_mode_cdf[libgav1::kNumFilterIntraPredictors] = ++value;
+  context.restoration_type_cdf[libgav1::kRestorationTypeSymbolCount] = ++value;
+  context.use_wiener_cdf[libgav1::kBooleanSymbolCount] = ++value;
+  context.use_sgrproj_cdf[libgav1::kBooleanSymbolCount] = ++value;
+  ResetAndVerifyCounters(&context);
+}
+
+void IncreasePartitionCounters(SymbolDecoderContext* symbol_context,
+                               int value) {
+  const int min_bsize_log2 = k4x4WidthLog2[kBlock8x8];
+  const int max_bsize_log2 = k4x4WidthLog2[kBlock128x128];
+  for (int block_size_log2 = min_bsize_log2; block_size_log2 <= max_bsize_log2;
+       ++block_size_log2) {
+    for (int context = 0; context < kPartitionContexts; ++context) {
+      const int cdf_size =
+          SymbolDecoderContext::PartitionCdfSize(block_size_log2);
+      symbol_context->partition_cdf[block_size_log2 - min_bsize_log2][context]
+                                   [cdf_size] += value;
+    }
+  }
+}
+
+void IncreasePaletteColorIndexCounters(SymbolDecoderContext* symbol_context,
+                                       int value) {
+  for (auto& palette_color_index_cdf_plane :
+       symbol_context->palette_color_index_cdf) {
+    for (int symbol_count = 0; symbol_count < kPaletteSizeSymbolCount;
+         ++symbol_count) {
+      const int cdf_size = symbol_count + kMinPaletteSize;
+      for (int context = 0; context < kPaletteColorIndexContexts; ++context) {
+        palette_color_index_cdf_plane[symbol_count][context][cdf_size] += value;
+      }
+    }
+  }
+}
+
+void IncreaseTxTypeCounters(SymbolDecoderContext* context, int value) {
+  for (int set_idx = kTransformSetIntra1; set_idx <= kTransformSetIntra2;
+       ++set_idx) {
+    auto tx_set = static_cast<TransformSet>(set_idx);
+    for (int tx_size = 0; tx_size < kNumExtendedTransformSizes; ++tx_size) {
+      for (int mode = 0; mode < kIntraPredictionModesY; ++mode) {
+        context->intra_tx_type_cdf[SymbolDecoderContext::TxTypeIndex(
+            tx_set)][tx_size][mode][kNumTransformTypesInSet[tx_set]] += value;
+      }
+    }
+  }
+
+  for (int set_idx = kTransformSetInter1; set_idx <= kTransformSetInter3;
+       ++set_idx) {
+    auto tx_set = static_cast<TransformSet>(set_idx);
+    for (int tx_size = 0; tx_size < kNumExtendedTransformSizes; ++tx_size) {
+      context->inter_tx_type_cdf[SymbolDecoderContext::TxTypeIndex(tx_set)]
+                                [tx_size][kNumTransformTypesInSet[tx_set]] +=
+          value;
+    }
+  }
+}
+
+void IncreaseTxDepthCounters(SymbolDecoderContext* symbol_context, int value) {
+  for (int context = 0; context < kTxDepthContexts; ++context) {
+    symbol_context->tx_depth_cdf[0][context][kMaxTxDepthSymbolCount - 1] +=
+        value;
+  }
+
+  for (int plane_category = 1; plane_category < 4; ++plane_category) {
+    for (int context = 0; context < kTxDepthContexts; ++context) {
+      symbol_context
+          ->tx_depth_cdf[plane_category][context][kMaxTxDepthSymbolCount] +=
+          value;
+    }
+  }
+}
+
+void IncreaseUVModeCounters(SymbolDecoderContext* symbol_context, int value) {
+  for (int cfl_allowed = 0; cfl_allowed < kBooleanSymbolCount; ++cfl_allowed) {
+    for (int mode = 0; mode < kIntraPredictionModesY; ++mode) {
+      symbol_context->uv_mode_cdf[cfl_allowed][mode][kIntraPredictionModesUV -
+                                                     (1 - cfl_allowed)] +=
+          value;
+    }
+  }
+}
+
+#define ASSIGN_COUNTER_2D(array, offset) \
+  do {                                   \
+    for (auto& d1 : context.array) {     \
+      d1[libgav1::offset] = ++value;     \
+    }                                    \
+  } while (false)
+
+TEST(SymbolDecoderContextTest, ResetCounters2d) {
+  libgav1::SymbolDecoderContext context = {};
+  context.Initialize(0);
+  int value = 0;
+  ASSIGN_COUNTER_2D(segment_id_cdf, kMaxSegments);
+  ASSIGN_COUNTER_2D(use_predicted_segment_id_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(skip_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(skip_mode_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(delta_lf_multi_cdf, kDeltaSymbolCount);
+  ASSIGN_COUNTER_2D(y_mode_cdf, kIntraPredictionModesY);
+  ASSIGN_COUNTER_2D(angle_delta_cdf, kAngleDeltaSymbolCount);
+  ASSIGN_COUNTER_2D(cfl_alpha_cdf, kCflAlphaSymbolCount);
+  ASSIGN_COUNTER_2D(use_filter_intra_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(tx_split_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(eob_pt_512_cdf, kEobPt512SymbolCount);
+  ASSIGN_COUNTER_2D(eob_pt_1024_cdf, kEobPt1024SymbolCount);
+  ASSIGN_COUNTER_2D(palette_y_size_cdf, kPaletteSizeSymbolCount);
+  ASSIGN_COUNTER_2D(has_palette_uv_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(palette_uv_size_cdf, kPaletteSizeSymbolCount);
+  ASSIGN_COUNTER_2D(is_inter_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(use_compound_reference_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(compound_reference_type_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(compound_prediction_mode_cdf,
+                    kNumCompoundInterPredictionModes);
+  ASSIGN_COUNTER_2D(new_mv_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(zero_mv_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(reference_mv_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(ref_mv_index_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(is_inter_intra_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(inter_intra_mode_cdf, kNumInterIntraModes);
+  ASSIGN_COUNTER_2D(is_wedge_inter_intra_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(wedge_index_cdf, kWedgeIndexSymbolCount);
+  ASSIGN_COUNTER_2D(use_obmc_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(motion_mode_cdf, kNumMotionModes);
+  ASSIGN_COUNTER_2D(is_explicit_compound_type_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(is_compound_type_average_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_2D(compound_type_cdf, kNumExplicitCompoundPredictionTypes);
+  ASSIGN_COUNTER_2D(interpolation_filter_cdf, kNumExplicitInterpolationFilters);
+  ASSIGN_COUNTER_2D(mv_joint_cdf, kNumMvJointTypes);
+  ResetAndVerifyCounters(&context);
+}
+
+#undef ASSIGN_COUNTER_2D
+
+#define ASSIGN_COUNTER_3D(array, offset) \
+  do {                                   \
+    for (auto& d1 : context.array) {     \
+      for (auto& d2 : d1) {              \
+        d2[libgav1::offset] = ++value;   \
+      }                                  \
+    }                                    \
+  } while (false)
+
+TEST(SymbolDecoderContextTest, ResetCounters3d) {
+  libgav1::SymbolDecoderContext context = {};
+  context.Initialize(0);
+  int value = 0;
+  ASSIGN_COUNTER_3D(intra_frame_y_mode_cdf, kIntraPredictionModesY);
+  ASSIGN_COUNTER_3D(all_zero_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(eob_pt_16_cdf, kEobPt16SymbolCount);
+  ASSIGN_COUNTER_3D(eob_pt_32_cdf, kEobPt32SymbolCount);
+  ASSIGN_COUNTER_3D(eob_pt_64_cdf, kEobPt64SymbolCount);
+  ASSIGN_COUNTER_3D(eob_pt_128_cdf, kEobPt128SymbolCount);
+  ASSIGN_COUNTER_3D(eob_pt_256_cdf, kEobPt256SymbolCount);
+  ASSIGN_COUNTER_3D(dc_sign_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(has_palette_y_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(compound_backward_reference_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(single_reference_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(mv_sign_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(mv_class_cdf, kMvClassSymbolCount);
+  ASSIGN_COUNTER_3D(mv_class0_bit_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(mv_class0_high_precision_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_3D(mv_fraction_cdf, kMvFractionSymbolCount);
+  ASSIGN_COUNTER_3D(mv_high_precision_cdf, kBooleanSymbolCount);
+  IncreasePartitionCounters(&context, value);
+  IncreaseTxTypeCounters(&context, value);
+  IncreaseTxDepthCounters(&context, value);
+  IncreaseUVModeCounters(&context, value);
+  ResetAndVerifyCounters(&context);
+}
+
+#undef ASSIGN_COUNTER_3D
+
+#define ASSIGN_COUNTER_4D(array, offset) \
+  do {                                   \
+    for (auto& d1 : context.array) {     \
+      for (auto& d2 : d1) {              \
+        for (auto& d3 : d2) {            \
+          d3[libgav1::offset] = ++value; \
+        }                                \
+      }                                  \
+    }                                    \
+  } while (false)
+
+TEST(SymbolDecoderContextTest, ResetCounters4d) {
+  libgav1::SymbolDecoderContext context = {};
+  context.Initialize(0);
+  int value = 0;
+  ASSIGN_COUNTER_4D(eob_extra_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_4D(coeff_base_eob_cdf, kCoeffBaseEobSymbolCount);
+  ASSIGN_COUNTER_4D(coeff_base_cdf, kCoeffBaseSymbolCount);
+  ASSIGN_COUNTER_4D(coeff_base_range_cdf, kCoeffBaseRangeSymbolCount);
+  ASSIGN_COUNTER_4D(compound_reference_cdf, kBooleanSymbolCount);
+  ASSIGN_COUNTER_4D(mv_class0_fraction_cdf, kMvFractionSymbolCount);
+  ASSIGN_COUNTER_4D(mv_bit_cdf, kBooleanSymbolCount);
+  IncreasePaletteColorIndexCounters(&context, value);
+  IncreaseTxTypeCounters(&context, value);
+  ResetAndVerifyCounters(&context);
+}
+
+#undef ASSIGN_COUNTER_4D
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/threading_strategy_test.cc b/src/threading_strategy_test.cc
new file mode 100644
index 0000000..beea36f
--- /dev/null
+++ b/src/threading_strategy_test.cc
@@ -0,0 +1,302 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/threading_strategy.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/str_cat.h"
+#include "gtest/gtest.h"
+#include "src/frame_scratch_buffer.h"
+#include "src/obu_parser.h"
+#include "src/utils/constants.h"
+#include "src/utils/threadpool.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+class ThreadingStrategyTest : public testing::Test {
+ protected:
+  ThreadingStrategy strategy_;
+  ObuFrameHeader frame_header_ = {};
+};
+
+TEST_F(ThreadingStrategyTest, MaxThreadEnforced) {
+  frame_header_.tile_info.tile_count = 32;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 32));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 32; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+TEST_F(ThreadingStrategyTest, UseAllThreadsForTiles) {
+  frame_header_.tile_info.tile_count = 8;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 8));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+TEST_F(ThreadingStrategyTest, RowThreads) {
+  frame_header_.tile_info.tile_count = 2;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 8));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  // Each tile should get 3 threads each.
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+TEST_F(ThreadingStrategyTest, RowThreadsUnequal) {
+  frame_header_.tile_info.tile_count = 2;
+
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 9));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  EXPECT_NE(strategy_.row_thread_pool(0), nullptr);
+  EXPECT_NE(strategy_.row_thread_pool(1), nullptr);
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+// Test a random combination of tile_count and thread_count.
+TEST_F(ThreadingStrategyTest, MultipleCalls) {
+  frame_header_.tile_info.tile_count = 2;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 8));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 8;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 8));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  // Row threads must have been reset.
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 8;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 16));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 8; ++i) {
+    // See ThreadingStrategy::Reset().
+#if defined(__ANDROID__)
+    if (i >= 4) {
+      EXPECT_EQ(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+      continue;
+    }
+#endif
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 4;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 16));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 4; ++i) {
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr);
+  }
+  // All the other row threads must be reset.
+  for (int i = 4; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 4;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 6));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  // First two tiles will get 1 thread each.
+  for (int i = 0; i < 2; ++i) {
+    // See ThreadingStrategy::Reset().
+#if defined(__ANDROID__)
+    if (i == 1) {
+      EXPECT_EQ(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+      continue;
+    }
+#endif
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+  }
+  // All the other row threads must be reset.
+  for (int i = 2; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 1));
+  EXPECT_EQ(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_EQ(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+// Tests the following order of calls (with thread count fixed at 4):
+//  * 1 Tile - 2 Tiles - 1 Tile.
+TEST_F(ThreadingStrategyTest, MultipleCalls2) {
+  frame_header_.tile_info.tile_count = 1;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 4));
+  // When there is only one tile, tile thread pool must be nullptr.
+  EXPECT_EQ(strategy_.tile_thread_pool(), nullptr);
+  EXPECT_NE(strategy_.row_thread_pool(0), nullptr);
+  for (int i = 1; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 2;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 4));
+  EXPECT_NE(strategy_.tile_thread_pool(), nullptr);
+  for (int i = 0; i < 2; ++i) {
+    // See ThreadingStrategy::Reset().
+#if defined(__ANDROID__)
+    if (i == 1) {
+      EXPECT_EQ(strategy_.row_thread_pool(i), nullptr) << "i = " << i;
+      continue;
+    }
+#endif
+    EXPECT_NE(strategy_.row_thread_pool(i), nullptr);
+  }
+  for (int i = 2; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+
+  frame_header_.tile_info.tile_count = 1;
+  ASSERT_TRUE(strategy_.Reset(frame_header_, 4));
+  EXPECT_EQ(strategy_.tile_thread_pool(), nullptr);
+  EXPECT_NE(strategy_.row_thread_pool(0), nullptr);
+  for (int i = 1; i < 8; ++i) {
+    EXPECT_EQ(strategy_.row_thread_pool(i), nullptr);
+  }
+  EXPECT_NE(strategy_.post_filter_thread_pool(), nullptr);
+}
+
+void VerifyFrameParallel(int thread_count, int tile_count, int tile_columns,
+                         int expected_frame_threads,
+                         const std::vector<int>& expected_tile_threads) {
+  ASSERT_EQ(expected_frame_threads, expected_tile_threads.size());
+  ASSERT_GT(thread_count, 1);
+  std::unique_ptr<ThreadPool> frame_thread_pool;
+  FrameScratchBufferPool frame_scratch_buffer_pool;
+  ASSERT_TRUE(InitializeThreadPoolsForFrameParallel(
+      thread_count, tile_count, tile_columns, &frame_thread_pool,
+      &frame_scratch_buffer_pool));
+  if (expected_frame_threads == 0) {
+    EXPECT_EQ(frame_thread_pool, nullptr);
+    return;
+  }
+  EXPECT_NE(frame_thread_pool.get(), nullptr);
+  EXPECT_EQ(frame_thread_pool->num_threads(), expected_frame_threads);
+  std::vector<std::unique_ptr<FrameScratchBuffer>> frame_scratch_buffers;
+  int actual_thread_count = frame_thread_pool->num_threads();
+  for (int i = 0; i < expected_frame_threads; ++i) {
+    SCOPED_TRACE(absl::StrCat("i: ", i));
+    frame_scratch_buffers.push_back(frame_scratch_buffer_pool.Get());
+    ThreadPool* const thread_pool =
+        frame_scratch_buffers.back()->threading_strategy.thread_pool();
+    if (expected_tile_threads[i] > 0) {
+      EXPECT_NE(thread_pool, nullptr);
+      EXPECT_EQ(thread_pool->num_threads(), expected_tile_threads[i]);
+      actual_thread_count += thread_pool->num_threads();
+    } else {
+      EXPECT_EQ(thread_pool, nullptr);
+    }
+  }
+  EXPECT_EQ(thread_count, actual_thread_count);
+  for (auto& frame_scratch_buffer : frame_scratch_buffers) {
+    frame_scratch_buffer_pool.Release(std::move(frame_scratch_buffer));
+  }
+}
+
+TEST(FrameParallelStrategyTest, FrameParallel) {
+  // This loop has thread_count <= 3 * tile count. So there should be no frame
+  // threads irrespective of the number of tile columns.
+  for (int thread_count = 2; thread_count <= 6; ++thread_count) {
+    VerifyFrameParallel(thread_count, /*tile_count=*/2, /*tile_columns=*/1,
+                        /*expected_frame_threads=*/0,
+                        /*expected_tile_threads=*/{});
+    VerifyFrameParallel(thread_count, /*tile_count=*/2, /*tile_columns=*/2,
+                        /*expected_frame_threads=*/0,
+                        /*expected_tile_threads=*/{});
+  }
+
+  // Equal number of tile threads for each frame thread.
+  VerifyFrameParallel(
+      /*thread_count=*/8, /*tile_count=*/1, /*tile_columns=*/1,
+      /*expected_frame_threads=*/4, /*expected_tile_threads=*/{1, 1, 1, 1});
+  VerifyFrameParallel(
+      /*thread_count=*/12, /*tile_count=*/2, /*tile_columns=*/2,
+      /*expected_frame_threads=*/4, /*expected_tile_threads=*/{2, 2, 2, 2});
+  VerifyFrameParallel(
+      /*thread_count=*/18, /*tile_count=*/2, /*tile_columns=*/2,
+      /*expected_frame_threads=*/6,
+      /*expected_tile_threads=*/{2, 2, 2, 2, 2, 2});
+  VerifyFrameParallel(
+      /*thread_count=*/16, /*tile_count=*/3, /*tile_columns=*/3,
+      /*expected_frame_threads=*/4, /*expected_tile_threads=*/{3, 3, 3, 3});
+
+  // Unequal number of tile threads for each frame thread.
+  VerifyFrameParallel(
+      /*thread_count=*/7, /*tile_count=*/1, /*tile_columns=*/1,
+      /*expected_frame_threads=*/3, /*expected_tile_threads=*/{2, 1, 1});
+  VerifyFrameParallel(
+      /*thread_count=*/14, /*tile_count=*/2, /*tile_columns=*/2,
+      /*expected_frame_threads=*/4, /*expected_tile_threads=*/{3, 3, 2, 2});
+  VerifyFrameParallel(
+      /*thread_count=*/20, /*tile_count=*/2, /*tile_columns=*/2,
+      /*expected_frame_threads=*/6,
+      /*expected_tile_threads=*/{3, 3, 2, 2, 2, 2});
+  VerifyFrameParallel(
+      /*thread_count=*/17, /*tile_count=*/3, /*tile_columns=*/3,
+      /*expected_frame_threads=*/4, /*expected_tile_threads=*/{4, 3, 3, 3});
+}
+
+TEST(FrameParallelStrategyTest, ThreadCountDoesNotExceedkMaxThreads) {
+  std::unique_ptr<ThreadPool> frame_thread_pool;
+  FrameScratchBufferPool frame_scratch_buffer_pool;
+  ASSERT_TRUE(InitializeThreadPoolsForFrameParallel(
+      /*thread_count=*/kMaxThreads + 10, /*tile_count=*/2, /*tile_columns=*/2,
+      &frame_thread_pool, &frame_scratch_buffer_pool));
+  EXPECT_NE(frame_thread_pool.get(), nullptr);
+  std::vector<std::unique_ptr<FrameScratchBuffer>> frame_scratch_buffers;
+  int actual_thread_count = frame_thread_pool->num_threads();
+  for (int i = 0; i < frame_thread_pool->num_threads(); ++i) {
+    SCOPED_TRACE(absl::StrCat("i: ", i));
+    frame_scratch_buffers.push_back(frame_scratch_buffer_pool.Get());
+    ThreadPool* const thread_pool =
+        frame_scratch_buffers.back()->threading_strategy.thread_pool();
+    if (thread_pool != nullptr) {
+      actual_thread_count += thread_pool->num_threads();
+    }
+  }
+  // In this case, the exact number of frame threads and tile threads depend on
+  // the value of kMaxThreads. So simply ensure that the total number of threads
+  // does not exceed kMaxThreads.
+  EXPECT_LE(actual_thread_count, kMaxThreads);
+  for (auto& frame_scratch_buffer : frame_scratch_buffers) {
+    frame_scratch_buffer_pool.Release(std::move(frame_scratch_buffer));
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/array_2d_test.cc b/src/utils/array_2d_test.cc
new file mode 100644
index 0000000..0535274
--- /dev/null
+++ b/src/utils/array_2d_test.cc
@@ -0,0 +1,248 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/array_2d.h"
+
+#include <cstdint>
+#include <memory>
+#include <new>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+#include "src/utils/compiler_attributes.h"
+
+#if LIBGAV1_MSAN
+#include <sanitizer/msan_interface.h>
+#endif
+
+namespace libgav1 {
+namespace {
+
+constexpr int kRows = 50;
+constexpr int kColumns = 200;
+
+TEST(Array2dViewTest, TestUint8) {
+  uint8_t data[kRows * kColumns] = {};
+  Array2DView<uint8_t> data2d(kRows, kColumns, data);
+
+  // Verify data.
+  data[kColumns] = 100;
+  data[kColumns + 1] = 101;
+  data[kColumns * 2 + 10] = 210;
+  data[kColumns * 2 + 40] = 240;
+  EXPECT_EQ(data2d[1][0], 100);
+  EXPECT_EQ(data2d[1][1], 101);
+  EXPECT_EQ(data2d[2][10], 210);
+  EXPECT_EQ(data2d[2][40], 240);
+
+  // Verify pointers.
+  EXPECT_EQ(data2d[10], data + 10 * kColumns);
+}
+
+TEST(Array2dViewTest, TestUint16) {
+  uint16_t data[kRows * kColumns] = {};
+  Array2DView<uint16_t> data2d(kRows, kColumns, data);
+
+  // Verify data.
+  data[kColumns] = 100;
+  data[kColumns + 1] = 101;
+  data[kColumns * 2 + 10] = 210;
+  data[kColumns * 2 + 40] = 240;
+  EXPECT_EQ(data2d[1][0], 100);
+  EXPECT_EQ(data2d[1][1], 101);
+  EXPECT_EQ(data2d[2][10], 210);
+  EXPECT_EQ(data2d[2][40], 240);
+
+  // Verify pointers.
+  EXPECT_EQ(data2d[10], data + 10 * kColumns);
+}
+
+TEST(Array2dViewTest, TestUint8Const) {
+  uint8_t data[kRows * kColumns] = {};
+  // Declared as const to provide a read-only view of |data|.
+  const Array2DView<uint8_t> data2d(kRows, kColumns, data);
+
+  // Verify data.
+  data[kColumns] = 100;
+  data[kColumns + 1] = 101;
+  data[kColumns * 2 + 10] = 210;
+  data[kColumns * 2 + 40] = 240;
+  EXPECT_EQ(data2d[1][0], 100);
+  EXPECT_EQ(data2d[1][1], 101);
+  EXPECT_EQ(data2d[2][10], 210);
+  EXPECT_EQ(data2d[2][40], 240);
+
+  // Verify pointers.
+  EXPECT_EQ(data2d[10], data + 10 * kColumns);
+}
+
+TEST(Array2dTest, TestUint8) {
+  Array2D<uint8_t> data2d;
+  ASSERT_TRUE(data2d.Reset(kRows, kColumns, true));
+
+  EXPECT_EQ(data2d.rows(), kRows);
+  EXPECT_EQ(data2d.columns(), kColumns);
+
+  // Verify pointers.
+  for (int i = 0; i < kRows; ++i) {
+    EXPECT_NE(data2d[i], nullptr);
+  }
+
+  // Verify data (must be zero initialized).
+  for (int i = 0; i < kRows; ++i) {
+    for (int j = 0; j < kColumns; ++j) {
+      EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
+    }
+  }
+
+  // Reset to a 2d array of smaller size with zero_initialize == false.
+  data2d[0][0] = 10;
+  ASSERT_TRUE(data2d.Reset(kRows - 1, kColumns - 1, false));
+
+  EXPECT_EQ(data2d.rows(), kRows - 1);
+  EXPECT_EQ(data2d.columns(), kColumns - 1);
+
+  // Verify pointers.
+  for (int i = 0; i < kRows - 1; ++i) {
+    EXPECT_NE(data2d[i], nullptr);
+  }
+
+  // Verify data (must be zero except for 0,0 because it was zero initialized in
+  // the previous call to Reset).
+  for (int i = 0; i < kRows - 1; ++i) {
+    for (int j = 0; j < kColumns - 1; ++j) {
+      if (i == 0 && j == 0) {
+        EXPECT_EQ(data2d[i][j], 10) << "Mismatch in [" << i << "][" << j << "]";
+      } else {
+        EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
+      }
+    }
+  }
+
+  // Reset to a 2d array of smaller size with zero_initialize == true.
+  ASSERT_TRUE(data2d.Reset(kRows - 2, kColumns - 2, true));
+
+  EXPECT_EQ(data2d.rows(), kRows - 2);
+  EXPECT_EQ(data2d.columns(), kColumns - 2);
+
+  // Verify pointers.
+  for (int i = 0; i < kRows - 2; ++i) {
+    EXPECT_NE(data2d[i], nullptr);
+  }
+
+  // Verify data (must be zero initialized).
+  for (int i = 0; i < kRows - 2; ++i) {
+    for (int j = 0; j < kColumns - 2; ++j) {
+      EXPECT_EQ(data2d[i][j], 0) << "Mismatch in [" << i << "][" << j << "]";
+    }
+  }
+}
+
+TEST(Array2dTest, TestUniquePtr1) {
+  // A simple class that sets an int value to 0 in the destructor.
+  class Cleaner {
+   public:
+    explicit Cleaner(int* value) : value_(value) {}
+    ~Cleaner() { *value_ = 0; }
+
+   private:
+    int* value_;
+  };
+  int value = 100;
+  Array2D<std::unique_ptr<Cleaner>> data2d;
+  ASSERT_TRUE(data2d.Reset(4, 4, true));
+  data2d[0][0].reset(new (std::nothrow) Cleaner(&value));
+  EXPECT_EQ(value, 100);
+  // Reset to a smaller size. Depending on the implementation, the data_ buffer
+  // may or may not be reused.
+  ASSERT_TRUE(data2d.Reset(2, 2, true));
+  // Reset to a much larger size. The data_ buffer will be reallocated.
+  ASSERT_TRUE(data2d.Reset(32, 32, true));
+  // The destructors of all elements in the former data_ buffer should have
+  // been invoked.
+  EXPECT_EQ(value, 0);
+}
+
+TEST(Array2dTest, TestUniquePtr2) {
+  // A simple class that sets an int value to 0 in the destructor.
+  class Cleaner {
+   public:
+    explicit Cleaner(int* value) : value_(value) {}
+    ~Cleaner() { *value_ = 0; }
+
+   private:
+    int* value_;
+  };
+  int value1 = 100;
+  int value2 = 200;
+  Array2D<std::unique_ptr<Cleaner>> data2d;
+  ASSERT_TRUE(data2d.Reset(4, 4, false));
+  data2d[0][0].reset(new (std::nothrow) Cleaner(&value1));
+  data2d[3][3].reset(new (std::nothrow) Cleaner(&value2));
+  EXPECT_EQ(value1, 100);
+  EXPECT_EQ(value2, 200);
+  // Reset to a smaller size. Whether or not the data_ buffer is reused, the
+  // destructors of all existing elements should be invoked.
+  ASSERT_TRUE(data2d.Reset(2, 2, false));
+  EXPECT_EQ(value1, 0);
+  EXPECT_EQ(value2, 0);
+}
+
+// Shows that std::is_standard_layout is not relevant to the default
+// initialization vs. value initialization issue, but std::is_trivial is.
+TEST(Array2dTest, TestStructInit) {
+  // Make one data member private so that this struct does not have a standard
+  // layout. This also makes the struct not a POD type.
+  struct Point {
+    int x;
+    int Y() const { return y; }
+
+   private:
+    int y;
+  };
+
+  EXPECT_TRUE(std::is_trivial<Point>::value);
+  EXPECT_FALSE(std::is_standard_layout<Point>::value);
+
+  // The Point structs in this array are default initialized.
+  Array2D<Point> data2d_default_init;
+  ASSERT_TRUE(data2d_default_init.Reset(kRows, kColumns, false));
+  // The Point structs in this array are value initialized (i.e., zero
+  // initialized).
+  Array2D<Point> data2d;
+  ASSERT_TRUE(data2d.Reset(kRows, kColumns, true));
+
+#if LIBGAV1_MSAN
+  // Use MemorySanitizer to check Reset(rows, columns, false) does not
+  // initialize the memory while Reset(rows, columns, true) does.
+  //
+  // __msan_test_shadow(const void *x, uptr size) returns the offset of the
+  // first (at least partially) poisoned byte in the range, or -1 if the whole
+  // range is good.
+  for (int i = 0; i < kRows; ++i) {
+    EXPECT_EQ(__msan_test_shadow(data2d_default_init[i],
+                                 sizeof(data2d_default_init[0][0]) * kColumns),
+              0);
+    EXPECT_EQ(__msan_test_shadow(data2d[i], sizeof(data2d[0][0]) * kColumns),
+              -1);
+    for (int j = 0; j < kColumns; ++j) {
+      EXPECT_EQ(data2d[i][j].x, 0);
+      EXPECT_EQ(data2d[i][j].Y(), 0);
+    }
+  }
+#endif
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/block_parameters_holder_test.cc b/src/utils/block_parameters_holder_test.cc
new file mode 100644
index 0000000..212eba5
--- /dev/null
+++ b/src/utils/block_parameters_holder_test.cc
@@ -0,0 +1,76 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/block_parameters_holder.h"
+
+#include "gtest/gtest.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(BlockParametersHolder, TestBasic) {
+  BlockParametersHolder holder;
+  ASSERT_TRUE(holder.Reset(20, 20));
+
+  // Get a BlockParameters object.
+  BlockParameters* const bp1 = holder.Get(10, 10, kBlock32x32);
+  ASSERT_NE(bp1, nullptr);
+  // Ensure that cache was filled appropriately. From (10, 10) to (17, 17)
+  // should be bp1 (10 + 4x4 width/height of 32x32 block is 18).
+  for (int i = 10; i < 18; ++i) {
+    for (int j = 10; j < 18; ++j) {
+      EXPECT_EQ(holder.Find(i, j), bp1)
+          << "Mismatch in (" << i << ", " << j << ")";
+    }
+  }
+
+  // Get the maximum number of BlockParameters objects.
+  for (int i = 0; i < 399; ++i) {
+    EXPECT_NE(holder.Get(10, 10, kBlock32x32), nullptr)
+        << "Mismatch in index " << i;
+  }
+
+  // Get() should now return nullptr since there are no more BlockParameters
+  // objects available.
+  EXPECT_EQ(holder.Get(10, 10, kBlock32x32), nullptr);
+
+  // Reset the holder to the same size.
+  ASSERT_TRUE(holder.Reset(20, 20));
+
+  // Get a BlockParameters object. This should be the same as bp1 since the
+  // holder was Reset to the same size.
+  BlockParameters* const bp2 = holder.Get(10, 10, kBlock32x32);
+  EXPECT_EQ(bp2, bp1);
+
+  // Reset the holder to a smaller size.
+  ASSERT_TRUE(holder.Reset(20, 10));
+
+  // Get a BlockParameters object. This should be the same as bp1 since the
+  // holder was Reset to a smaller size.
+  BlockParameters* const bp3 = holder.Get(0, 0, kBlock32x32);
+  EXPECT_EQ(bp3, bp1);
+
+  // Reset the holder to a larger size.
+  ASSERT_TRUE(holder.Reset(30, 30));
+
+  // Get a BlockParameters object. This may or may not be the same as bp1 since
+  // the holder was Reset to a larger size.
+  BlockParameters* const bp4 = holder.Get(0, 0, kBlock32x32);
+  EXPECT_NE(bp4, nullptr);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/blocking_counter_test.cc b/src/utils/blocking_counter_test.cc
new file mode 100644
index 0000000..1b6e7f5
--- /dev/null
+++ b/src/utils/blocking_counter_test.cc
@@ -0,0 +1,127 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/blocking_counter.h"
+
+#include <array>
+#include <memory>
+
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/utils/threadpool.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr int kNumWorkers = 10;
+constexpr int kNumJobs = 20;
+
+TEST(BlockingCounterTest, BasicFunctionality) {
+  std::unique_ptr<ThreadPool> pool = ThreadPool::Create(kNumWorkers);
+  BlockingCounter counter(kNumJobs);
+  std::array<bool, kNumJobs> done = {};
+
+  // Schedule the jobs.
+  for (int i = 0; i < kNumJobs; ++i) {
+    pool->Schedule([&counter, &done, i]() {
+      absl::SleepFor(absl::Seconds(1));
+      done[i] = true;
+      counter.Decrement();
+    });
+  }
+
+  // Wait for the jobs to complete. This should always return true.
+  ASSERT_TRUE(counter.Wait());
+
+  // Make sure the jobs were actually complete.
+  for (const auto& job_done : done) {
+    EXPECT_TRUE(job_done);
+  }
+}
+
+TEST(BlockingCounterTest, IncrementBy) {
+  std::unique_ptr<ThreadPool> pool = ThreadPool::Create(kNumWorkers);
+  BlockingCounter counter(0);
+  std::array<bool, kNumJobs> done = {};
+
+  // Schedule the jobs.
+  for (int i = 0; i < kNumJobs; ++i) {
+    counter.IncrementBy(1);
+    pool->Schedule([&counter, &done, i]() {
+      absl::SleepFor(absl::Seconds(1));
+      done[i] = true;
+      counter.Decrement();
+    });
+  }
+
+  // Wait for the jobs to complete. This should always return true.
+  ASSERT_TRUE(counter.Wait());
+
+  // Make sure the jobs were actually complete.
+  for (const auto& job_done : done) {
+    EXPECT_TRUE(job_done);
+  }
+}
+
+TEST(BlockingCounterWithStatusTest, BasicFunctionality) {
+  std::unique_ptr<ThreadPool> pool = ThreadPool::Create(kNumWorkers);
+  BlockingCounterWithStatus counter(kNumJobs);
+  std::array<bool, kNumJobs> done = {};
+
+  // Schedule the jobs.
+  for (int i = 0; i < kNumJobs; ++i) {
+    pool->Schedule([&counter, &done, i]() {
+      absl::SleepFor(absl::Seconds(1));
+      done[i] = true;
+      counter.Decrement(true);
+    });
+  }
+
+  // Wait for the jobs to complete. This should return true since all the jobs
+  // reported |job_succeeded| as true.
+  ASSERT_TRUE(counter.Wait());
+
+  // Make sure the jobs were actually complete.
+  for (const auto& job_done : done) {
+    EXPECT_TRUE(job_done);
+  }
+}
+
+TEST(BlockingCounterWithStatusTest, BasicFunctionalityWithStatus) {
+  std::unique_ptr<ThreadPool> pool = ThreadPool::Create(kNumWorkers);
+  BlockingCounterWithStatus counter(kNumJobs);
+  std::array<bool, kNumJobs> done = {};
+
+  // Schedule the jobs.
+  for (int i = 0; i < kNumJobs; ++i) {
+    pool->Schedule([&counter, &done, i]() {
+      absl::SleepFor(absl::Seconds(1));
+      done[i] = true;
+      counter.Decrement(i != 10);
+    });
+  }
+
+  // Wait for the jobs to complete. This should return false since one of the
+  // jobs reported |job_succeeded| as false.
+  ASSERT_FALSE(counter.Wait());
+
+  // Make sure the jobs were actually complete.
+  for (const auto& job_done : done) {
+    EXPECT_TRUE(job_done);
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/common_test.cc b/src/utils/common_test.cc
new file mode 100644
index 0000000..fdb218d
--- /dev/null
+++ b/src/utils/common_test.cc
@@ -0,0 +1,604 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/common.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "gtest/gtest.h"
+#include "src/utils/constants.h"
+#include "src/utils/memory.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+int BitLength(int64_t n) {
+  int count = 0;
+  while (n != 0) {
+    ++count;
+    n >>= 1;
+  }
+  return count;
+}
+
+TEST(CommonUtilsTest, Align) {
+  for (int i = 0; i <= 8; ++i) {
+    const int alignment = 1 << i;
+    SCOPED_TRACE("alignment: " + std::to_string(alignment));
+    EXPECT_EQ(Align(0, alignment), 0);
+    EXPECT_EQ(Align(1, alignment), alignment);
+    EXPECT_EQ(Align(alignment + 1, alignment), 2 * alignment);
+    if (i > 1) {
+      EXPECT_EQ(Align(alignment - 1, alignment), alignment);
+      EXPECT_EQ(Align(2 * alignment - 1, alignment), 2 * alignment);
+    }
+  }
+}
+
+TEST(CommonUtilsTest, AlignAddr) {
+  auto buf = MakeAlignedUniquePtr<uint8_t>(/*alignment=*/1024, 512);
+  ASSERT_NE(buf, nullptr);
+  auto* const bufptr = buf.get();
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(bufptr) % 1024, 0);
+
+  for (int i = 0; i <= 8; ++i) {
+    const int alignment = 1 << i;
+    ASSERT_LE(alignment, 1024);
+    SCOPED_TRACE("alignment: " + std::to_string(alignment));
+    EXPECT_EQ(AlignAddr(nullptr, alignment), nullptr);
+    EXPECT_EQ(AlignAddr(bufptr, alignment), bufptr);
+    EXPECT_EQ(AlignAddr(bufptr + 1, alignment), bufptr + alignment);
+    EXPECT_EQ(AlignAddr(bufptr + alignment + 1, alignment),
+              bufptr + 2 * alignment);
+    if (i > 1) {
+      EXPECT_EQ(AlignAddr(bufptr + alignment - 1, alignment),
+                bufptr + alignment);
+      EXPECT_EQ(AlignAddr(bufptr + 2 * alignment - 1, alignment),
+                bufptr + 2 * alignment);
+    }
+  }
+}
+
+TEST(CommonUtilsTest, Clip3) {
+  // Value <= lower boundary.
+  EXPECT_EQ(Clip3(10, 20, 30), 20);
+  EXPECT_EQ(Clip3(20, 20, 30), 20);
+  // Value >= higher boundary.
+  EXPECT_EQ(Clip3(40, 20, 30), 30);
+  EXPECT_EQ(Clip3(30, 20, 30), 30);
+  // Value within boundary.
+  EXPECT_EQ(Clip3(25, 20, 30), 25);
+  // Clipping based on bitdepth (clamp between 0 and 2^bitdepth - 1). Make sure
+  // that the resulting values are always in the pixel range for the
+  // corresponding bitdepth.
+  static constexpr int bitdepths[] = {8, 10, 12};
+  static constexpr int pixels[] = {100, 500, 5000, -100, -500, -5000};
+  for (const auto& bitdepth : bitdepths) {
+    for (const auto& pixel : pixels) {
+      const int clipped_pixel = Clip3(pixel, 0, (1 << bitdepth) - 1);
+      EXPECT_GE(clipped_pixel, 0)
+          << "Clip3 mismatch for bitdepth: " << bitdepth << " pixel: " << pixel;
+      EXPECT_LE(clipped_pixel, (1 << bitdepth) - 1)
+          << "Clip3 mismatch for bitdepth: " << bitdepth << " pixel: " << pixel;
+    }
+  }
+}
+
+template <typename Pixel>
+void TestExtendLine(int width, const int left, int right, Pixel left_value,
+                    Pixel right_value) {
+  constexpr int size = 1000;
+  ASSERT_LE(width + left + right, size);
+  Pixel line[size];
+  Pixel* line_start = line + left;
+  line_start[0] = left_value;
+  line_start[width - 1] = right_value;
+  ExtendLine<Pixel>(line_start, width, left, right);
+  for (int x = 0; x < left; x++) {
+    EXPECT_EQ(left_value, line[x]) << "Left side mismatch at x: " << x;
+  }
+  for (int x = 0; x < right; x++) {
+    EXPECT_EQ(right_value, line[left + width + x])
+        << "Right side mismatch at x: " << x;
+  }
+}
+
+TEST(CommonUtilsTest, ExtendLine) {
+  TestExtendLine<uint8_t>(300, 0, 0, 31, 13);
+  TestExtendLine<uint8_t>(100, 10, 20, 31, 13);
+  TestExtendLine<uint8_t>(257, 31, 77, 59, 255);
+  TestExtendLine<uint16_t>(600, 0, 0, 1234, 4321);
+  TestExtendLine<uint16_t>(200, 55, 88, 12345, 54321);
+  TestExtendLine<uint16_t>(2, 99, 333, 257, 513);
+}
+
+template <typename T>
+void TestMemSetBlock(int rows, int columns, ptrdiff_t stride, T value) {
+  constexpr int size = 1000;
+  T block[size];
+  static_assert(sizeof(T) == 1, "");
+  ASSERT_LE(rows * stride, size);
+  ASSERT_LE(columns, stride);
+  MemSetBlock<T>(rows, columns, value, block, stride);
+  for (int y = 0; y < rows; y++) {
+    for (int x = 0; x < columns; x++) {
+      EXPECT_EQ(value, block[y * stride + x])
+          << "Mismatch at y: " << y << " x: " << x;
+    }
+  }
+}
+
+TEST(CommonUtilsTest, MemSetBlock) {
+  TestMemSetBlock<bool>(15, 28, 29, true);
+  TestMemSetBlock<bool>(17, 1, 24, false);
+  TestMemSetBlock<bool>(7, 2, 13, true);
+  TestMemSetBlock<int8_t>(35, 17, 19, 123);
+  TestMemSetBlock<uint8_t>(19, 16, 16, 234);
+}
+
+template <typename T>
+void TestSetBlock(int rows, int columns, ptrdiff_t stride, T value) {
+  constexpr int size = 1000;
+  T block[size];
+  ASSERT_LE(rows * stride, size);
+  ASSERT_LE(columns, stride);
+  SetBlock<T>(rows, columns, value, block, stride);
+  for (int y = 0; y < rows; y++) {
+    for (int x = 0; x < columns; x++) {
+      EXPECT_EQ(value, block[y * stride + x])
+          << "Mismatch at y: " << y << " x: " << x;
+    }
+  }
+}
+
+TEST(CommonUtilsTest, SetBlock) {
+  // Test 1-byte block set.
+  TestSetBlock<bool>(15, 28, 29, true);
+  TestSetBlock<bool>(17, 1, 24, false);
+  TestSetBlock<bool>(7, 2, 13, true);
+  TestSetBlock<int8_t>(35, 17, 19, 123);
+  TestSetBlock<uint8_t>(19, 16, 16, 234);
+  // Test 2-byte block set.
+  TestSetBlock<int16_t>(23, 27, 28, 1234);
+  TestSetBlock<uint16_t>(13, 39, 44, 4321);
+  // Test 4-byte block set.
+  TestSetBlock<int>(14, 7, 7, 12345);
+  TestSetBlock<int>(33, 4, 15, 54321);
+  // Test pointer block set.
+  int data;
+  TestSetBlock<int*>(23, 8, 25, &data);
+}
+
+TEST(CommonUtilsTest, CountTrailingZeros) {
+  EXPECT_EQ(CountTrailingZeros(0x1), 0);
+  EXPECT_EQ(CountTrailingZeros(0x3), 0);
+  EXPECT_EQ(CountTrailingZeros(0x7), 0);
+  EXPECT_EQ(CountTrailingZeros(0xF), 0);
+  EXPECT_EQ(CountTrailingZeros(0x2), 1);
+  EXPECT_EQ(CountTrailingZeros(0x6), 1);
+  EXPECT_EQ(CountTrailingZeros(0xE), 1);
+  EXPECT_EQ(CountTrailingZeros(0x4), 2);
+  EXPECT_EQ(CountTrailingZeros(0xC), 2);
+  EXPECT_EQ(CountTrailingZeros(0x8), 3);
+  EXPECT_EQ(CountTrailingZeros(0x10), 4);
+  EXPECT_EQ(CountTrailingZeros(0x30), 4);
+  EXPECT_EQ(CountTrailingZeros(0x70), 4);
+  EXPECT_EQ(CountTrailingZeros(0xF0), 4);
+  EXPECT_EQ(CountTrailingZeros(0x20), 5);
+  EXPECT_EQ(CountTrailingZeros(0x60), 5);
+  EXPECT_EQ(CountTrailingZeros(0xE0), 5);
+  EXPECT_EQ(CountTrailingZeros(0x40), 6);
+  EXPECT_EQ(CountTrailingZeros(0xC0), 6);
+  EXPECT_EQ(CountTrailingZeros(0x80), 7);
+  EXPECT_EQ(CountTrailingZeros(0x31), 0);
+  EXPECT_EQ(CountTrailingZeros(0x32), 1);
+  EXPECT_EQ(CountTrailingZeros(0x34), 2);
+  EXPECT_EQ(CountTrailingZeros(0x38), 3);
+  EXPECT_EQ(CountTrailingZeros(0x310), 4);
+  EXPECT_EQ(CountTrailingZeros(0x320), 5);
+  EXPECT_EQ(CountTrailingZeros(0x340), 6);
+  EXPECT_EQ(CountTrailingZeros(0x380), 7);
+}
+
+TEST(CommonUtilsTest, FloorLog2) {
+  // Powers of 2.
+  EXPECT_EQ(FloorLog2(1), 0);
+  EXPECT_EQ(FloorLog2(2), 1);
+  EXPECT_EQ(FloorLog2(8), 3);
+  EXPECT_EQ(FloorLog2(64), 6);
+  // Powers of 2 +/- 1.
+  EXPECT_EQ(FloorLog2(9), 3);
+  EXPECT_EQ(FloorLog2(15), 3);
+  EXPECT_EQ(FloorLog2(63), 5);
+  // Large value, smaller than 32 bit.
+  EXPECT_EQ(FloorLog2(0x7fffffff), 30);
+  EXPECT_EQ(FloorLog2(0x80000000), 31);
+  // Larger than 32 bit.
+  EXPECT_EQ(FloorLog2(uint64_t{0x7fffffffffffffff}), 62);
+  EXPECT_EQ(FloorLog2(uint64_t{0x8000000000000000}), 63);
+  EXPECT_EQ(FloorLog2(uint64_t{0xffffffffffffffff}), 63);
+}
+
+TEST(CommonUtilsTest, CeilLog2) {
+  // Even though log2(0) is -inf, here we explicitly define it to be 0.
+  EXPECT_EQ(CeilLog2(0), 0);
+  // Powers of 2.
+  EXPECT_EQ(CeilLog2(1), 0);
+  EXPECT_EQ(CeilLog2(2), 1);
+  EXPECT_EQ(CeilLog2(8), 3);
+  EXPECT_EQ(CeilLog2(64), 6);
+  // Powers of 2 +/- 1.
+  EXPECT_EQ(CeilLog2(9), 4);
+  EXPECT_EQ(CeilLog2(15), 4);
+  EXPECT_EQ(CeilLog2(63), 6);
+  // Large value.
+  EXPECT_EQ(CeilLog2(0x7fffffff), 31);
+}
+
+TEST(CommonUtilsTest, RightShiftWithCeiling) {
+  // Shift 1 bit.
+  EXPECT_EQ(RightShiftWithCeiling(1, 1), 1);
+  EXPECT_EQ(RightShiftWithCeiling(2, 1), 1);
+  EXPECT_EQ(RightShiftWithCeiling(3, 1), 2);
+  EXPECT_EQ(RightShiftWithCeiling(4, 1), 2);
+  EXPECT_EQ(RightShiftWithCeiling(5, 1), 3);
+  // Shift 2 bits.
+  EXPECT_EQ(RightShiftWithCeiling(1, 2), 1);
+  EXPECT_EQ(RightShiftWithCeiling(2, 2), 1);
+  EXPECT_EQ(RightShiftWithCeiling(3, 2), 1);
+  EXPECT_EQ(RightShiftWithCeiling(4, 2), 1);
+  EXPECT_EQ(RightShiftWithCeiling(5, 2), 2);
+  // Shift 20 bits.
+  EXPECT_EQ(RightShiftWithCeiling(1, 20), 1);
+  EXPECT_EQ(RightShiftWithCeiling((1 << 20) - 1, 20), 1);
+  EXPECT_EQ(RightShiftWithCeiling(1 << 20, 20), 1);
+  EXPECT_EQ(RightShiftWithCeiling((1 << 20) + 1, 20), 2);
+  EXPECT_EQ(RightShiftWithCeiling((1 << 21) - 1, 20), 2);
+}
+
+template <typename Input, typename Output>
+void VerifyRightShiftWithRounding(const Input* const values,
+                                  const int* const bits,
+                                  const Output* const rounded_values,
+                                  size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    const Output rounded_value = RightShiftWithRounding(values[i], bits[i]);
+    EXPECT_EQ(rounded_value, rounded_values[i]) << "Mismatch at index " << i;
+    // Rounding reduces the bit length by |bits[i]| - 1.
+    EXPECT_LE(BitLength(rounded_value), BitLength(values[i]) - (bits[i] - 1))
+        << "Mismatch at index " << i;
+  }
+}
+
+TEST(CommonUtilTest, RightShiftWithRoundingInt32) {
+  static constexpr int32_t values[] = {5, 203, 204, 255, 40000, 50000};
+  static constexpr int bits[] = {0, 3, 3, 3, 12, 12};
+  static constexpr int32_t rounded_values[] = {5, 25, 26, 32, 10, 12};
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(bits), "");
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(rounded_values), "");
+  VerifyRightShiftWithRounding<int32_t, int32_t>(values, bits, rounded_values,
+                                                 ABSL_ARRAYSIZE(values));
+}
+
+TEST(CommonUtilTest, RightShiftWithRoundingUint32) {
+  static constexpr uint32_t values[] = {5,     203,   204,       255,
+                                        40000, 50000, 0x7fffffff};
+  static constexpr int bits[] = {0, 3, 3, 3, 12, 12, 20};
+  static constexpr uint32_t rounded_values[] = {5, 25, 26, 32, 10, 12, 2048};
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(bits), "");
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(rounded_values), "");
+  VerifyRightShiftWithRounding<uint32_t, uint32_t>(values, bits, rounded_values,
+                                                   ABSL_ARRAYSIZE(values));
+}
+
+TEST(CommonUtilTest, RightShiftWithRoundingInt64) {
+  static constexpr int64_t values[] = {5,     203,   204,        255,
+                                       40000, 50000, 0x7fffffff, 0x8fffffff};
+  static constexpr int bits[] = {0, 3, 3, 3, 12, 12, 20, 20};
+  static constexpr int32_t rounded_values[] = {5,  25, 26,   32,
+                                               10, 12, 2048, 2304};
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(bits), "");
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(rounded_values), "");
+  VerifyRightShiftWithRounding<int64_t, int32_t>(values, bits, rounded_values,
+                                                 ABSL_ARRAYSIZE(values));
+}
+
+template <typename Input>
+void VerifyRightShiftWithRoundingSigned(const Input* const values,
+                                        const int* const bits,
+                                        const int32_t* const rounded_values,
+                                        int count) {
+  for (int i = 0; i < count; ++i) {
+    int32_t rounded_value = RightShiftWithRoundingSigned(values[i], bits[i]);
+    EXPECT_EQ(rounded_value, rounded_values[i]) << "Mismatch at index " << i;
+    rounded_value = RightShiftWithRoundingSigned(-values[i], bits[i]);
+    EXPECT_EQ(rounded_value, -rounded_values[i]) << "Mismatch at index " << i;
+  }
+}
+
+TEST(CommonUtilTest, RightShiftWithRoundingSignedInt32) {
+  static constexpr int32_t values[] = {203, 204, 255, 40000, 50000};
+  static constexpr int bits[] = {3, 3, 3, 12, 12};
+  static constexpr int32_t rounded_values[] = {25, 26, 32, 10, 12};
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(bits), "");
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(rounded_values), "");
+  VerifyRightShiftWithRoundingSigned<int32_t>(values, bits, rounded_values,
+                                              ABSL_ARRAYSIZE(values));
+}
+
+TEST(CommonUtilTest, RightShiftWithRoundingSignedInt64) {
+  static constexpr int64_t values[] = {203,   204,        255,       40000,
+                                       50000, 0x7fffffff, 0x8fffffff};
+  static constexpr int bits[] = {3, 3, 3, 12, 12, 20, 20};
+  static constexpr int32_t rounded_values[] = {25, 26, 32, 10, 12, 2048, 2304};
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(bits), "");
+  static_assert(ABSL_ARRAYSIZE(values) == ABSL_ARRAYSIZE(rounded_values), "");
+  VerifyRightShiftWithRoundingSigned<int64_t>(values, bits, rounded_values,
+                                              ABSL_ARRAYSIZE(values));
+}
+
+TEST(CommonUtilTest, GetResidualBufferSize) {
+  // No subsampling.
+  EXPECT_EQ(GetResidualBufferSize(64, 64, 0, 0, 2),
+            /* 2*(64*64*3/1 + 32*4) = */ 24832);
+  // Only X is subsampled.
+  EXPECT_EQ(GetResidualBufferSize(64, 64, 1, 0, 2),
+            /* 2*(64*64*2/1 + 32*4) = */ 16640);
+  // Only Y is subsampled.
+  EXPECT_EQ(GetResidualBufferSize(64, 64, 0, 1, 2),
+            /* 2*(64*64*2/1 + 32*4) = */ 16640);
+  // Both X and Y are subsampled.
+  EXPECT_EQ(GetResidualBufferSize(64, 64, 1, 1, 2),
+            /* 2*(64*64*3/2 + 32*4) = */ 12544);
+}
+
+//------------------------------------------------------------------------------
+// Tests for bitstream util functions
+
+TEST(BitstreamUtilTest, IsIntraFrame) {
+  EXPECT_TRUE(IsIntraFrame(kFrameKey));
+  EXPECT_TRUE(IsIntraFrame(kFrameIntraOnly));
+  EXPECT_FALSE(IsIntraFrame(kFrameInter));
+  EXPECT_FALSE(IsIntraFrame(kFrameSwitch));
+}
+
+TEST(BitstreamUtilTest, GetTransformClass) {
+  static constexpr TransformClass expected_classes[kNumTransformTypes] = {
+      kTransformClass2D,       kTransformClass2D,
+      kTransformClass2D,       kTransformClass2D,
+      kTransformClass2D,       kTransformClass2D,
+      kTransformClass2D,       kTransformClass2D,
+      kTransformClass2D,       kTransformClass2D,
+      kTransformClassVertical, kTransformClassHorizontal,
+      kTransformClassVertical, kTransformClassHorizontal,
+      kTransformClassVertical, kTransformClassHorizontal,
+  };
+  for (int i = 0; i < kNumTransformTypes; ++i) {
+    EXPECT_EQ(GetTransformClass(static_cast<TransformType>(i)),
+              expected_classes[i])
+        << "Mismatch at index " << i;
+  }
+}
+
+TEST(BitstreamUtilTest, RowOrColumn4x4ToPixel) {
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneY, 0), 40);
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneY, 1),
+            40);  // Subsampling should have no effect on Y plane.
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneU, 0), 40);
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneU, 1), 20);
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneV, 0), 40);
+  EXPECT_EQ(RowOrColumn4x4ToPixel(10, kPlaneV, 1), 20);
+}
+
+TEST(BitstreamUtilTest, GetPlaneType) {
+  EXPECT_EQ(GetPlaneType(kPlaneY), kPlaneTypeY);
+  EXPECT_EQ(GetPlaneType(kPlaneU), kPlaneTypeUV);
+  EXPECT_EQ(GetPlaneType(kPlaneV), kPlaneTypeUV);
+}
+
+TEST(BitstreamUtils, IsDirectionalMode) {
+  static constexpr bool is_directional_modes[kNumPredictionModes] = {
+      false, true,  true,  true,  true,  true,  true,  true,  true,
+      false, false, false, false, false, false, false, false, false,
+      false, false, false, false, false, false, false, false,
+  };
+  for (int i = 0; i < kNumPredictionModes; ++i) {
+    EXPECT_EQ(IsDirectionalMode(static_cast<PredictionMode>(i)),
+              is_directional_modes[i])
+        << "Mismatch at index " << i;
+  }
+}
+
+TEST(BitstreamUtils, GetRelativeDistance) {
+  // Both order_hint_bits and order_hint_shift_bits are zero. (a and b must be
+  // zero.)
+  EXPECT_EQ(GetRelativeDistance(0, 0, 0), 0);
+  EXPECT_EQ(GetRelativeDistance(10, 20, 27), -10);
+
+  EXPECT_EQ(GetRelativeDistance(2, 1, 30), 1);
+  EXPECT_EQ(GetRelativeDistance(2, 1, 29), 1);
+
+  EXPECT_EQ(GetRelativeDistance(1, 2, 30), -1);
+  EXPECT_EQ(GetRelativeDistance(1, 2, 29), -1);
+
+  // With an order_hint_bits of 4 and an order_hint_shift_bits of 28, 16 is the
+  // same as 0, 17 is the same as 1, etc. The most positive distance is 7, and
+  // the most negative distance is -8.
+
+  EXPECT_EQ(GetRelativeDistance(2, 6, 28), -4);
+  EXPECT_EQ(GetRelativeDistance(6, 2, 28), 4);
+  // 18 - 14 = 4.
+  EXPECT_EQ(GetRelativeDistance(2, 14, 28), 4);
+  // 14 - 18 = -4.
+  EXPECT_EQ(GetRelativeDistance(14, 2, 28), -4);
+  // If a and b are exactly 8 apart, GetRelativeDistance() cannot tell whether
+  // a is before or after b. GetRelativeDistance(a, b) and
+  // GetRelativeDistance(b, a) are both -8.
+  // 1 - 9 = -8.
+  EXPECT_EQ(GetRelativeDistance(1, 9, 28), -8);
+  // 9 - 17 = -8.
+  EXPECT_EQ(GetRelativeDistance(9, 1, 28), -8);
+
+  // With an order_hint_bits of 5 and an order_hint_shift_bits of 27, 32 is the
+  // same as 0, 33 is the same as 1, etc. The most positive distance is 15, and
+  // the most negative distance is -16.
+
+  // 31 - 32 = -1.
+  EXPECT_EQ(GetRelativeDistance(31, 0, 27), -1);
+  // 32 - 31 = 1.
+  EXPECT_EQ(GetRelativeDistance(0, 31, 27), 1);
+  // 30 - 33 = -3.
+  EXPECT_EQ(GetRelativeDistance(30, 1, 27), -3);
+  // 33 - 30 = 3.
+  EXPECT_EQ(GetRelativeDistance(1, 30, 27), 3);
+  // 25 - 36 = -11.
+  EXPECT_EQ(GetRelativeDistance(25, 4, 27), -11);
+  // 36 - 25 = 11.
+  EXPECT_EQ(GetRelativeDistance(4, 25, 27), 11);
+  // 15 - 0 = 15.
+  EXPECT_EQ(GetRelativeDistance(15, 0, 27), 15);
+  // If a and b are exactly 16 apart, GetRelativeDistance() cannot tell whether
+  // a is before or after b. GetRelativeDistance(a, b) and
+  // GetRelativeDistance(b, a) are both -16.
+  // 16 - 32 = -16.
+  EXPECT_EQ(GetRelativeDistance(16, 0, 27), -16);
+  // 0 - 16 = -16.
+  EXPECT_EQ(GetRelativeDistance(0, 16, 27), -16);
+}
+
+TEST(BitstreamUtils, ApplySign) {
+  // ApplyPositive(0) = 0
+  EXPECT_EQ(ApplySign(0, 0), 0);
+  // ApplyNegative(0) = 0
+  EXPECT_EQ(ApplySign(0, -1), 0);
+
+  // ApplyPositive(1) = 1
+  EXPECT_EQ(ApplySign(1, 0), 1);
+  // ApplyNegative(1) = -1
+  EXPECT_EQ(ApplySign(1, -1), -1);
+
+  // ApplyPositive(-1) = -1
+  EXPECT_EQ(ApplySign(-1, 0), -1);
+  // ApplyNegative(-1) = 1
+  EXPECT_EQ(ApplySign(-1, -1), 1);
+
+  // ApplyPositive(1234) = 1234
+  EXPECT_EQ(ApplySign(1234, 0), 1234);
+  // ApplyNegative(1234) = -1234
+  EXPECT_EQ(ApplySign(1234, -1), -1234);
+
+  // ApplyPositive(-1234) = -1234
+  EXPECT_EQ(ApplySign(-1234, 0), -1234);
+  // ApplyNegative(-1234) = 1234
+  EXPECT_EQ(ApplySign(-1234, -1), 1234);
+}
+
+// 7.9.3. (without the clamp for numerator and denominator).
+int SpecGetMvProjectionKernel(int mv, int numerator, int denominator) {
+  int value = mv * numerator * kProjectionMvDivisionLookup[denominator];
+  if (value >= 0) {
+    value += 1 << 13;
+    value >>= 14;
+  } else {
+    value = -value;
+    value += 1 << 13;
+    value >>= 14;
+    value = -value;
+  }
+  if (value < (-(1 << 14) + 1)) value = -(1 << 14) + 1;
+  if (value > (1 << 14) - 1) value = (1 << 14) - 1;
+  return value;
+}
+
+void SpecGetMvProjectionNoClamp(const MotionVector& mv, int numerator,
+                                int denominator, MotionVector* projection_mv) {
+  for (int i = 0; i < 2; ++i) {
+    projection_mv->mv[i] =
+        SpecGetMvProjectionKernel(mv.mv[i], numerator, denominator);
+  }
+}
+
+TEST(BitstreamUtils, GetMvProjection) {
+  const int16_t mvs[5][2] = {
+      {0, 0}, {11, 73}, {-84, 272}, {733, -827}, {-472, -697}};
+  for (auto& mv_value : mvs) {
+    for (int numerator = -kMaxFrameDistance; numerator <= kMaxFrameDistance;
+         ++numerator) {
+      for (int denominator = 0; denominator <= kMaxFrameDistance;
+           ++denominator) {
+        MotionVector mv, projection_mv, spec_projection_mv;
+        mv.mv[0] = mv_value[0];
+        mv.mv[1] = mv_value[1];
+        GetMvProjection(mv, numerator, kProjectionMvDivisionLookup[denominator],
+                        &projection_mv);
+        SpecGetMvProjectionNoClamp(mv, numerator, denominator,
+                                   &spec_projection_mv);
+        EXPECT_EQ(projection_mv.mv32, spec_projection_mv.mv32);
+      }
+    }
+  }
+}
+
+// 7.9.4.
+int SpecProject(int value, int delta, int dst_sign) {
+  constexpr int kMiSizeLog2 = 2;
+  const int sign = (dst_sign == 0) ? 1 : dst_sign;
+  int offset;
+  if (delta >= 0) {
+    offset = delta >> (3 + 1 + kMiSizeLog2);
+  } else {
+    offset = -((-delta) >> (3 + 1 + kMiSizeLog2));
+  }
+  return value + sign * offset;
+}
+
+TEST(BitstreamUtils, Project) {
+  for (int value = -10; value <= 10; ++value) {
+    for (int delta = -256; delta <= 256; ++delta) {
+      for (int dst_sign = -1; dst_sign <= 0; ++dst_sign) {
+        EXPECT_EQ(Project(value, delta, dst_sign),
+                  SpecProject(value, delta, dst_sign));
+      }
+    }
+  }
+}
+
+TEST(BitstreamUtils, IsBlockSmallerThan8x8) {
+  static constexpr bool is_block_smaller_than8x8[kMaxBlockSizes] = {
+      true,  true,  false, true,  false, false, false, false,
+      false, false, false, false, false, false, false, false,
+      false, false, false, false, false, false,
+  };
+  for (int i = 0; i < kMaxBlockSizes; ++i) {
+    EXPECT_EQ(IsBlockSmallerThan8x8(static_cast<BlockSize>(i)),
+              is_block_smaller_than8x8[i])
+        << "Mismatch at index " << i;
+  }
+}
+
+TEST(BitstreamUtils, TransformSizeToSquareTransformIndex) {
+  EXPECT_EQ(TransformSizeToSquareTransformIndex(kTransformSize4x4), 0);
+  EXPECT_EQ(TransformSizeToSquareTransformIndex(kTransformSize8x8), 1);
+  EXPECT_EQ(TransformSizeToSquareTransformIndex(kTransformSize16x16), 2);
+  EXPECT_EQ(TransformSizeToSquareTransformIndex(kTransformSize32x32), 3);
+  EXPECT_EQ(TransformSizeToSquareTransformIndex(kTransformSize64x64), 4);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/cpu_test.cc b/src/utils/cpu_test.cc
new file mode 100644
index 0000000..3a01b33
--- /dev/null
+++ b/src/utils/cpu_test.cc
@@ -0,0 +1,248 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/cpu.h"
+
+#if defined(__linux__)
+#include <unistd.h>
+
+#include <cerrno>
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#endif  // defined(__linux__)
+
+#include "gtest/gtest.h"
+#include "src/utils/logging.h"
+
+namespace libgav1 {
+namespace {
+
+#if defined(__linux__)
+
+// Sample code for getting the number of performance CPU cores. The following
+// sources were consulted:
+// * https://www.kernel.org/doc/html/latest/admin-guide/cputopology.html
+// * cpu-hotplug.txt: CPU hotplug Support in Linux(tm) Kernel
+//   https://lwn.net/Articles/537570/
+// * https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
+// * Android bionic source code of get_nprocs():
+//   libc/bionic/sysinfo.cpp
+// * glibc 2.30 source code of get_nprocs():
+//   sysdeps/unix/sysv/linux/getsysstats.c
+//
+// Tested on:
+// * Asus Nexus 7 2013: Qualcomm Snapdragon 600, 32-bit Android 6.0.1
+//   (Marshmallow). Brings cores online and offline dynamically. (The tablet
+//   has 4 cores. "0", "0-1", "0-2", and "0-3" have all been observed in the
+//   /sys/devices/system/cpu/online file.) This causes the number of cores
+//   currently online to potentially be lower than the number of cores that can
+//   be brought online quickly.
+// * General Mobile 4G: Qualcomm Snapdragon 410, 32-bit Android 7.1.1 (Nougat).
+// * Motorola Moto G5 Plus: Qualcomm Snapdragon 625, 32-bit Android 8.1.0
+//   (Oreo).
+// * Motorola Moto G7 Play: Qualcomm Snapdragon 632, 32-bit Android 9 (Pie).
+//   All 8 cores have the same cpuinfo_max_freq (1804800), but there are two
+//   values of cpuinfo_min_freq: cores 0-3 have 614400 and cores 4-7 have
+//   633600. We would need to check cpuinfo_min_freq to differentiate the two
+//   kinds of cores (Qualcomm Kryo 250 Gold and Qualcomm Kryo 250 Silver).
+// * Pixel 2 XL: Qualcomm Snapdragon 835, 64-bit Android 9 (Pie).
+// * Pixel 3: Qualcomm Snapdragon 845, 64-bit Android 9 (Pie).
+// * Pixel 3a: Qualcomm Snapdragon 670, 64-bit Android 9 (Pie).
+// * Samsung Galaxy S6: Samsung Exynos 7 Octa (7420), 64-bit Android 7.0
+//   (Nougat).
+// * Samsung Galaxy S8+ (SM-G955FD): Samsung Exynos 8895, 64-bit Android 8.0.0.
+//
+// Note: The sample code needs to use the 'long' type because it is the return
+// type of the Standard C Library function strtol(). The ClangTidy warnings are
+// suppressed with NOLINT(google-runtime-int) comments.
+
+// Returns the number of online processor cores.
+int GetNumberOfProcessorsOnline() {
+  // See https://developer.android.com/ndk/guides/cpu-features.
+  long num_cpus = sysconf(_SC_NPROCESSORS_ONLN);  // NOLINT(google-runtime-int)
+  if (num_cpus < 0) {
+    LIBGAV1_DLOG(ERROR, "sysconf(_SC_NPROCESSORS_ONLN) failed: %s.",
+                 strerror(errno));
+    return 0;
+  }
+  // It is safe to cast num_cpus to int. sysconf(_SC_NPROCESSORS_ONLN) returns
+  // the return value of get_nprocs(), which is an int.
+  return static_cast<int>(num_cpus);
+}
+
+// These CPUs support heterogeneous multiprocessing.
+#if defined(__arm__) || defined(__aarch64__)
+
+// A helper function used by GetNumberOfPerformanceCoresOnline().
+//
+// Returns the cpuinfo_max_freq value (in kHz) of the given CPU. Returns 0 on
+// failure.
+long GetCpuinfoMaxFreq(int cpu_index) {  // NOLINT(google-runtime-int)
+  char buffer[128];
+  const int rv = snprintf(
+      buffer, sizeof(buffer),
+      "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu_index);
+  if (rv < 0 || rv >= sizeof(buffer)) {
+    LIBGAV1_DLOG(ERROR, "snprintf failed, or |buffer| is too small.");
+    return 0;
+  }
+  FILE* file = fopen(buffer, "r");
+  if (file == nullptr) {
+    LIBGAV1_DLOG(ERROR, "fopen(\"%s\", \"r\") failed: %s.", buffer,
+                 strerror(errno));
+    return 0;
+  }
+  char* const str = fgets(buffer, sizeof(buffer), file);
+  fclose(file);
+  if (str == nullptr) {
+    LIBGAV1_DLOG(ERROR, "fgets failed.");
+    return 0;
+  }
+  const long freq = strtol(str, nullptr, 10);  // NOLINT(google-runtime-int)
+  if (freq <= 0 || freq == LONG_MAX) {
+    LIBGAV1_DLOG(ERROR,
+                 "No conversion can be performed, or the converted value is "
+                 "invalid: %ld.",
+                 freq);
+    return 0;
+  }
+  return freq;
+}
+
+// Returns the number of performance CPU cores that are online. The number of
+// efficiency CPU cores is subtracted from the total number of CPU cores. Uses
+// cpuinfo_max_freq to determine whether a CPU is a performance core or an
+// efficiency core.
+//
+// This function is not perfect. For example, the Snapdragon 632 SoC used in
+// Motorola Moto G7 has performance and efficiency cores with the same
+// cpuinfo_max_freq but different cpuinfo_min_freq. This function fails to
+// differentiate the two kinds of cores and reports all the cores as
+// performance cores.
+int GetNumberOfPerformanceCoresOnline() {
+  // Get the online CPU list. Some examples of the online CPU list are:
+  //   "0-7"
+  //   "0"
+  //   "0-1,2,3,4-7"
+  char online[512];
+  FILE* file = fopen("/sys/devices/system/cpu/online", "r");
+  if (file == nullptr) {
+    LIBGAV1_DLOG(ERROR,
+                 "fopen(\"/sys/devices/system/cpu/online\", \"r\") failed: %s.",
+                 strerror(errno));
+    return 0;
+  }
+  char* const str = fgets(online, sizeof(online), file);
+  fclose(file);
+  file = nullptr;
+  if (str == nullptr) {
+    LIBGAV1_DLOG(ERROR, "fgets failed.");
+    return 0;
+  }
+  LIBGAV1_DLOG(INFO, "The online CPU list is %s", online);
+
+  // Count the number of the slowest CPUs. Some SoCs such as Snapdragon 855
+  // have performance cores with different max frequencies, so only the slowest
+  // CPUs are efficiency cores. If we count the number of the fastest CPUs, we
+  // will fail to count the second fastest performance cores.
+  long slowest_cpu_freq = LONG_MAX;  // NOLINT(google-runtime-int)
+  int num_slowest_cpus = 0;
+  int num_cpus = 0;
+  const char* cp = online;
+  int range_begin = -1;
+  while (true) {
+    char* str_end;
+    const int cpu = static_cast<int>(strtol(cp, &str_end, 10));
+    if (str_end == cp) {
+      break;
+    }
+    cp = str_end;
+    if (*cp == '-') {
+      range_begin = cpu;
+    } else {
+      if (range_begin == -1) {
+        range_begin = cpu;
+      }
+
+      num_cpus += cpu - range_begin + 1;
+      for (int i = range_begin; i <= cpu; ++i) {
+        const long freq = GetCpuinfoMaxFreq(i);  // NOLINT(google-runtime-int)
+        if (freq <= 0) {
+          return 0;
+        }
+        LIBGAV1_DLOG(INFO, "cpu%d max frequency is %ld kHz.", i, freq);
+        if (freq < slowest_cpu_freq) {
+          slowest_cpu_freq = freq;
+          num_slowest_cpus = 0;
+        }
+        if (freq == slowest_cpu_freq) {
+          ++num_slowest_cpus;
+        }
+      }
+
+      range_begin = -1;
+    }
+    if (*cp == '\0') {
+      break;
+    }
+    ++cp;
+  }
+
+  LIBGAV1_DLOG(INFO, "There are %d CPU cores.", num_cpus);
+  LIBGAV1_DLOG(INFO,
+               "%d CPU cores are the slowest, with max frequency %ld kHz.",
+               num_slowest_cpus, slowest_cpu_freq);
+  // If there are faster CPU cores than the slowest CPU cores, exclude the
+  // slowest CPU cores.
+  if (num_slowest_cpus < num_cpus) {
+    num_cpus -= num_slowest_cpus;
+  }
+  return num_cpus;
+}
+
+#else
+
+// Assume symmetric multiprocessing.
+int GetNumberOfPerformanceCoresOnline() {
+  return GetNumberOfProcessorsOnline();
+}
+
+#endif
+
+#endif  // defined(__linux__)
+
+/*
+  Run this test with logging enabled on an Android device:
+  64-bit Android:
+    tests/run_android_test.sh --test cpu --enable_asserts
+  32-bit Android:
+    tests/run_android_test.sh --test cpu --arch arm \
+        --enable_asserts
+*/
+TEST(CpuTest, GetNumberOfPerformanceCoresOnline) {
+#if defined(__linux__)
+  const int num_cpus = GetNumberOfProcessorsOnline();
+  ASSERT_NE(num_cpus, 0);
+  LIBGAV1_DLOG(INFO, "There are %d cores online.", num_cpus);
+  const int num_performance_cpus = GetNumberOfPerformanceCoresOnline();
+  ASSERT_NE(num_performance_cpus, 0);
+  LIBGAV1_DLOG(INFO, "There are %d performance cores online.",
+               num_performance_cpus);
+#endif  // defined(__linux__)
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/entropy_decoder_test.cc b/src/utils/entropy_decoder_test.cc
new file mode 100644
index 0000000..9d23088
--- /dev/null
+++ b/src/utils/entropy_decoder_test.cc
@@ -0,0 +1,1259 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/entropy_decoder.h"
+
+#include <cstdint>
+#include <cstdio>
+
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+#include "src/utils/entropy_decoder_test_data.inc"
+
+class EntropyDecoderTest : public testing::Test {
+ protected:
+  // If compile_time is true, tests
+  //     bool EntropyDecoder::ReadSymbol(uint16_t* cdf).
+  // Otherwise, tests
+  //     int EntropyDecoder::ReadSymbol(uint16_t* cdf, int symbol_count)
+  // with symbol_count=2.
+  template <bool compile_time>
+  void TestReadSymbolBoolean(int num_runs);
+
+  // For N = 3..16 (except 15):
+  //     template <bool compile_time>
+  //     void TestReadSymbolN(int num_runs);
+  //
+  // If compile_time is true, tests
+  //     int EntropyDecoder::ReadSymbol<N>(uint16_t* const cdf).
+  // Otherwise, tests
+  //     int EntropyDecoder::ReadSymbol(uint16_t* cdf, int symbol_count)
+  // with symbol_count=N.
+  //
+  // NOTE: symbol_count=15 is not tested because AV1 does not use it.
+  template <bool compile_time>
+  void TestReadSymbol3(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol4(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol5(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol6(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol7(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol8(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol9(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol10(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol11(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol12(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol13(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol14(int num_runs);
+
+  template <bool compile_time>
+  void TestReadSymbol16(int num_runs);
+};
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbolBoolean(int num_runs) {
+  static constexpr int kSymbols[4][4] = {{0, 0, 1, 1},  //
+                                         {0, 1, 1, 0},  //
+                                         {1, 0, 1, 0},  //
+                                         {1, 0, 0, 1}};
+  absl::Duration elapsed_time;
+  bool symbols[1024 * 4 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbolBoolean,
+                          kNumBytesTestReadSymbolBoolean,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][3] = {
+        {16384, 0, 0},
+        {32768 - 8386, 0, 0},
+        {32768 - 24312, 0, 0},
+        {16384, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 1024; ++i) {
+      for (int j = 0; j < 4; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 2) != 0;
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbolBooleanCompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbolBoolean(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 1024; ++i) {
+    for (int j = 0; j < 4; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol3(int num_runs) {
+  static constexpr int kSymbols[6][4] = {{0, 2, 1, 2},  //
+                                         {1, 1, 2, 1},  //
+                                         {2, 0, 0, 0},  //
+                                         {0, 2, 0, 2},  //
+                                         {1, 2, 1, 0},  //
+                                         {2, 1, 1, 0}};
+  absl::Duration elapsed_time;
+  int symbols[1024 * 6 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol3, kNumBytesTestReadSymbol3,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][4] = {
+        // pdf: 1/3, 1/3, 1/3
+        {32768 - 10923, 32768 - 21845, 0, 0},
+        // pdf: 1/6, 2/6, 3/6
+        {32768 - 5461, 32768 - 16384, 0, 0},
+        // pdf: 2/6, 3/6, 1/6
+        {32768 - 10923, 32768 - 27307, 0, 0},
+        // pdf: 3/6, 1/6, 2/6
+        {32768 - 16384, 32768 - 21845, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 1024; ++i) {
+      for (int j = 0; j < 6; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<3>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 3);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol3CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol3(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 1024; ++i) {
+    for (int j = 0; j < 6; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol4(int num_runs) {
+  static constexpr int kSymbols[8][4] = {{0, 0, 3, 3},  //
+                                         {0, 0, 2, 2},  //
+                                         {1, 1, 0, 0},  //
+                                         {1, 2, 1, 1},  //
+                                         {2, 2, 3, 2},  //
+                                         {2, 3, 2, 1},  //
+                                         {3, 3, 0, 0},  //
+                                         {3, 3, 1, 1}};
+  absl::Duration elapsed_time;
+  int symbols[1024 * 8 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol4, kNumBytesTestReadSymbol4,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][5] = {
+        // pdf: 1/4, 1/4, 1/4, 1/4
+        {32768 - 8192, 32768 - 16384, 32768 - 24576, 0, 0},
+        // pdf: 2/8, 1/8, 2/8, 3/8
+        {32768 - 8192, 32768 - 12288, 32768 - 20480, 0, 0},
+        // pdf: 1/4, 1/4, 1/4, 1/4
+        {32768 - 8192, 32768 - 16384, 32768 - 24576, 0, 0},
+        // pdf: 2/8, 3/8, 2/8, 1/8
+        {32768 - 8192, 32768 - 20480, 32768 - 28672, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 1024; ++i) {
+      for (int j = 0; j < 8; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<4>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 4);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol4CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol4(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 1024; ++i) {
+    for (int j = 0; j < 8; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol5(int num_runs) {
+  static constexpr int kSymbols[10][4] = {{0, 0, 4, 4},  //
+                                          {0, 1, 3, 3},  //
+                                          {1, 2, 2, 2},  //
+                                          {1, 3, 1, 1},  //
+                                          {2, 4, 0, 0},  //
+                                          {2, 0, 4, 3},  //
+                                          {3, 1, 3, 2},  //
+                                          {3, 2, 2, 1},  //
+                                          {4, 3, 1, 2},  //
+                                          {4, 0, 4, 2}};
+  absl::Duration elapsed_time;
+  int symbols[320 * 10 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol5, kNumBytesTestReadSymbol5,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][6] = {
+        // pdf: 1/5, 1/5, 1/5, 1/5, 1/5
+        {32768 - 6554, 32768 - 13107, 32768 - 19661, 32768 - 26214, 0, 0},
+        // pdf: 3/10, 2/10, 2/10, 2/10, 1/10
+        {32768 - 9830, 32768 - 16384, 32768 - 22938, 32768 - 29491, 0, 0},
+        // pdf: 1/10, 2/10, 2/10, 2/10, 3/10
+        {32768 - 3277, 32768 - 9830, 32768 - 16384, 32768 - 22938, 0, 0},
+        // pdf: 1/10, 2/10, 4/10, 2/10, 1/10
+        {32768 - 3277, 32768 - 9830, 32768 - 22938, 32768 - 29491, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 320; ++i) {
+      for (int j = 0; j < 10; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<5>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 5);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol5CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol5(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 320; ++i) {
+    for (int j = 0; j < 10; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol6(int num_runs) {
+  static constexpr int kSymbols[12][4] = {{0, 0, 5, 5},  //
+                                          {0, 1, 4, 4},  //
+                                          {1, 2, 3, 3},  //
+                                          {1, 3, 2, 2},  //
+                                          {2, 4, 1, 1},  //
+                                          {2, 5, 0, 0},  //
+                                          {3, 0, 5, 4},  //
+                                          {3, 1, 4, 3},  //
+                                          {4, 2, 3, 2},  //
+                                          {4, 3, 2, 1},  //
+                                          {5, 4, 1, 3},  //
+                                          {5, 0, 5, 2}};
+  absl::Duration elapsed_time;
+  int symbols[256 * 12 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol6, kNumBytesTestReadSymbol6,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][7] = {
+        // pmf: 1/6, 1/6, 1/6, 1/6, 1/6, 1/6
+        {32768 - 5461, 32768 - 10923, 32768 - 16384, 32768 - 21845,
+         32768 - 27307, 0, 0},
+        // pmf: 3/12, 2/12, 2/12, 2/12, 2/12, 1/12
+        {32768 - 8192, 32768 - 13653, 32768 - 19115, 32768 - 24576,
+         32768 - 30037, 0, 0},
+        // pmf: 1/12, 2/12, 2/12, 2/12, 2/12, 3/12
+        {32768 - 2731, 32768 - 8192, 32768 - 13653, 32768 - 19115,
+         32768 - 24576, 0, 0},
+        // pmf: 1/12, 2/12, 3/12, 3/12, 2/12, 1/12
+        {32768 - 2731, 32768 - 8192, 32768 - 16384, 32768 - 24576,
+         32768 - 30037, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 256; ++i) {
+      for (int j = 0; j < 12; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<6>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 6);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol6CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol6(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 256; ++i) {
+    for (int j = 0; j < 12; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol7(int num_runs) {
+  static constexpr int kSymbols[14][4] = {{0, 4, 6, 3},  //
+                                          {1, 5, 5, 2},  //
+                                          {2, 6, 4, 1},  //
+                                          {3, 0, 3, 0},  //
+                                          {4, 1, 2, 6},  //
+                                          {5, 2, 1, 5},  //
+                                          {6, 3, 0, 4},  //
+                                          {0, 0, 6, 5},  //
+                                          {2, 1, 4, 3},  //
+                                          {4, 3, 6, 1},  //
+                                          {6, 5, 2, 4},  //
+                                          {1, 0, 5, 2},  //
+                                          {3, 2, 3, 2},  //
+                                          {5, 4, 5, 3}};
+  absl::Duration elapsed_time;
+  int symbols[1024 * 14 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol7, kNumBytesTestReadSymbol7,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][8] = {
+        // pdf: 1/7, 1/7, 1/7, 1/7, 1/7, 1/7, 1/7
+        {32768 - 4681, 32768 - 9362, 32768 - 14043, 32768 - 18725,
+         32768 - 23406, 32768 - 28087, 0, 0},
+        // pdf: 3/14, 2/14, 2/14, 2/14, 2/14, 2/14, 1/14
+        {32768 - 7022, 32768 - 11703, 32768 - 16384, 32768 - 21065,
+         32768 - 25746, 32768 - 30427, 0, 0},
+        // pdf: 1/14, 1/14, 2/14, 2/14, 2/14, 3/14, 3/14
+        {32768 - 2341, 32768 - 4681, 32768 - 9362, 32768 - 14043, 32768 - 18725,
+         32768 - 25746, 0, 0},
+        // pdf: 1/14, 2/14, 3/14, 3/14, 2/14, 2/14, 1/14
+        {32768 - 2341, 32768 - 7022, 32768 - 14043, 32768 - 21065,
+         32768 - 25746, 32768 - 30427, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 1024; ++i) {
+      for (int j = 0; j < 14; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<7>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 7);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol7CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol7(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 1024; ++i) {
+    for (int j = 0; j < 14; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol8(int num_runs) {
+  static constexpr int kSymbols[16][4] = {{0, 4, 7, 3},  //
+                                          {1, 5, 6, 2},  //
+                                          {2, 6, 5, 1},  //
+                                          {3, 7, 4, 0},  //
+                                          {4, 0, 3, 7},  //
+                                          {5, 1, 2, 6},  //
+                                          {6, 2, 1, 5},  //
+                                          {7, 3, 0, 4},  //
+                                          {0, 0, 6, 5},  //
+                                          {2, 1, 4, 3},  //
+                                          {4, 3, 6, 4},  //
+                                          {6, 5, 2, 2},  //
+                                          {1, 0, 7, 3},  //
+                                          {3, 2, 5, 5},  //
+                                          {5, 4, 7, 2},  //
+                                          {7, 6, 3, 4}};
+  absl::Duration elapsed_time;
+  int symbols[1024 * 16 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol8, kNumBytesTestReadSymbol8,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][9] = {
+        // pdf: 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8
+        {32768 - 4096, 32768 - 8192, 32768 - 12288, 32768 - 16384,
+         32768 - 20480, 32768 - 24576, 32768 - 28672, 0, 0},
+        // pdf: 3/16, 2/16, 2/16, 2/16, 2/16, 2/16, 2/16, 1/16
+        {32768 - 6144, 32768 - 10240, 32768 - 14336, 32768 - 18432,
+         32768 - 22528, 32768 - 26624, 32768 - 30720, 0, 0},
+        // pdf: 1/16, 1/16, 2/16, 2/16, 2/16, 2/16, 3/16, 3/16
+        {32768 - 2048, 32768 - 4096, 32768 - 8192, 32768 - 12288, 32768 - 16384,
+         32768 - 20480, 32768 - 26624, 0, 0},
+        // pdf: 1/16, 1/16, 3/16, 3/16, 3/16, 3/16, 1/16, 1/16
+        {32768 - 2048, 32768 - 4096, 32768 - 10240, 32768 - 16384,
+         32768 - 22528, 32768 - 28672, 32768 - 30720, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 1024; ++i) {
+      for (int j = 0; j < 16; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<8>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 8);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol8CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol8(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 1024; ++i) {
+    for (int j = 0; j < 16; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol9(int num_runs) {
+  static constexpr int kSymbols[18][4] = {{0, 4, 8, 3},  //
+                                          {1, 5, 7, 2},  //
+                                          {2, 6, 6, 1},  //
+                                          {3, 7, 5, 0},  //
+                                          {4, 8, 4, 8},  //
+                                          {5, 0, 3, 7},  //
+                                          {6, 1, 2, 6},  //
+                                          {7, 2, 1, 5},  //
+                                          {8, 3, 0, 4},  //
+                                          {0, 0, 8, 7},  //
+                                          {2, 1, 6, 5},  //
+                                          {4, 3, 4, 3},  //
+                                          {6, 5, 2, 1},  //
+                                          {8, 7, 7, 6},  //
+                                          {1, 0, 5, 4},  //
+                                          {3, 2, 3, 2},  //
+                                          {5, 4, 1, 4},  //
+                                          {7, 6, 8, 4}};
+  absl::Duration elapsed_time;
+  int symbols[128 * 18 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol9, kNumBytesTestReadSymbol9,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][10] = {
+        // pmf: 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9
+        {32768 - 3641, 32768 - 7282, 32768 - 10923, 32768 - 14564,
+         32768 - 18204, 32768 - 21845, 32768 - 25486, 32768 - 29127, 0, 0},
+        // pmf: 3/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 1/18
+        {32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 16384,
+         32768 - 20025, 32768 - 23666, 32768 - 27307, 32768 - 30948, 0, 0},
+        // pmf: 1/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 3/18
+        {32768 - 1820, 32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 16384,
+         32768 - 20025, 32768 - 23666, 32768 - 27307, 0, 0},
+        // pmf: 1/18, 2/18, 2/18, 2/18, 4/18, 2/18, 2/18, 2/18, 1/18
+        {32768 - 1820, 32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 20025,
+         32768 - 23666, 32768 - 27307, 32768 - 30948, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 128; ++i) {
+      for (int j = 0; j < 18; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<9>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 9);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol9CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol9(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 128; ++i) {
+    for (int j = 0; j < 18; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol10(int num_runs) {
+  static constexpr int kSymbols[20][4] = {{0, 5, 9, 4},  //
+                                          {1, 6, 8, 3},  //
+                                          {2, 7, 7, 2},  //
+                                          {3, 8, 6, 1},  //
+                                          {4, 9, 5, 0},  //
+                                          {5, 0, 4, 9},  //
+                                          {6, 1, 3, 8},  //
+                                          {7, 2, 2, 7},  //
+                                          {8, 3, 1, 6},  //
+                                          {9, 4, 0, 5},  //
+                                          {0, 0, 9, 7},  //
+                                          {2, 1, 8, 5},  //
+                                          {4, 3, 6, 3},  //
+                                          {6, 5, 4, 1},  //
+                                          {8, 7, 2, 8},  //
+                                          {1, 0, 9, 6},  //
+                                          {3, 2, 7, 4},  //
+                                          {5, 4, 5, 2},  //
+                                          {7, 6, 3, 5},  //
+                                          {9, 8, 1, 4}};
+  absl::Duration elapsed_time;
+  int symbols[96 * 20 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol10, kNumBytesTestReadSymbol10,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][11] = {
+        // pmf: 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10
+        {32768 - 3277, 32768 - 6554, 32768 - 9830, 32768 - 13107, 32768 - 16384,
+         32768 - 19661, 32768 - 22938, 32768 - 26214, 32768 - 29491, 0, 0},
+        // pmf: 3/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 1/20
+        {32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 14746,
+         32768 - 18022, 32768 - 21299, 32768 - 24576, 32768 - 27853,
+         32768 - 31130, 0, 0},
+        // pmf: 1/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 3/20
+        {32768 - 1638, 32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 14746,
+         32768 - 18022, 32768 - 21299, 32768 - 24576, 32768 - 27853, 0, 0},
+        // pmf: 1/20, 2/20, 2/20, 2/20, 3/20, 3/20, 2/20, 2/20, 2/20, 1/20
+        {32768 - 1638, 32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 16384,
+         32768 - 21299, 32768 - 24576, 32768 - 27853, 32768 - 31130, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 96; ++i) {
+      for (int j = 0; j < 20; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<10>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 10);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol10CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol10(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 96; ++i) {
+    for (int j = 0; j < 20; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol11(int num_runs) {
+  static constexpr int kSymbols[22][4] = {{0, 6, 10, 5},   //
+                                          {1, 7, 9, 4},    //
+                                          {2, 8, 8, 3},    //
+                                          {3, 9, 7, 2},    //
+                                          {4, 10, 6, 1},   //
+                                          {5, 0, 5, 0},    //
+                                          {6, 1, 4, 10},   //
+                                          {7, 2, 3, 9},    //
+                                          {8, 3, 2, 8},    //
+                                          {9, 4, 1, 7},    //
+                                          {10, 5, 0, 6},   //
+                                          {0, 0, 10, 9},   //
+                                          {2, 1, 8, 7},    //
+                                          {4, 3, 6, 5},    //
+                                          {6, 5, 4, 3},    //
+                                          {8, 7, 2, 1},    //
+                                          {10, 9, 10, 8},  //
+                                          {1, 0, 9, 6},    //
+                                          {3, 2, 7, 4},    //
+                                          {5, 4, 5, 2},    //
+                                          {7, 6, 3, 5},    //
+                                          {9, 8, 1, 5}};
+  absl::Duration elapsed_time;
+  int symbols[96 * 22 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol11, kNumBytesTestReadSymbol11,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][12] = {
+        // pmf: 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11
+        {32768 - 2979, 32768 - 5958, 32768 - 8937, 32768 - 11916, 32768 - 14895,
+         32768 - 17873, 32768 - 20852, 32768 - 23831, 32768 - 26810,
+         32768 - 29789, 0, 0},
+        // pmf: 3/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 1/22
+        {32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405,
+         32768 - 16384, 32768 - 19363, 32768 - 22342, 32768 - 25321,
+         32768 - 28300, 32768 - 31279, 0, 0},
+        // pmf: 1/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 3/22
+        {32768 - 1489, 32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405,
+         32768 - 16384, 32768 - 19363, 32768 - 22342, 32768 - 25321,
+         32768 - 28300, 0, 0},
+        // pmf: 1/22, 2/22, 2/22, 2/22, 2/22, 4/22, 2/22, 2/22, 2/22, 2/22, 1/22
+        {32768 - 1489, 32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405,
+         32768 - 19363, 32768 - 22342, 32768 - 25321, 32768 - 28300,
+         32768 - 31279, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 96; ++i) {
+      for (int j = 0; j < 22; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<11>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 11);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol11CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol11(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 96; ++i) {
+    for (int j = 0; j < 22; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol12(int num_runs) {
+  static constexpr int kSymbols[24][4] = {{0, 6, 11, 5},   //
+                                          {1, 7, 10, 4},   //
+                                          {2, 8, 9, 3},    //
+                                          {3, 9, 8, 2},    //
+                                          {4, 10, 7, 1},   //
+                                          {5, 11, 6, 0},   //
+                                          {6, 0, 5, 11},   //
+                                          {7, 1, 4, 10},   //
+                                          {8, 2, 3, 9},    //
+                                          {9, 3, 2, 8},    //
+                                          {10, 4, 1, 7},   //
+                                          {11, 5, 0, 6},   //
+                                          {0, 0, 11, 9},   //
+                                          {2, 1, 10, 7},   //
+                                          {4, 3, 8, 5},    //
+                                          {6, 5, 6, 3},    //
+                                          {8, 7, 4, 1},    //
+                                          {10, 9, 2, 10},  //
+                                          {1, 0, 11, 8},   //
+                                          {3, 2, 9, 6},    //
+                                          {5, 4, 7, 4},    //
+                                          {7, 6, 5, 2},    //
+                                          {9, 8, 3, 6},    //
+                                          {11, 10, 1, 5}};
+  absl::Duration elapsed_time;
+  int symbols[80 * 24 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol12, kNumBytesTestReadSymbol12,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][13] = {
+        // pmf: 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12,
+        // 1/12,
+        // 1/12
+        {32768 - 2731, 32768 - 5461, 32768 - 8192, 32768 - 10923, 32768 - 13653,
+         32768 - 16384, 32768 - 19115, 32768 - 21845, 32768 - 24576,
+         32768 - 27307, 32768 - 30037, 0, 0},
+        // pmf: 3/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24,
+        // 2/24,
+        // 1/24
+        {32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288, 32768 - 15019,
+         32768 - 17749, 32768 - 20480, 32768 - 23211, 32768 - 25941,
+         32768 - 28672, 32768 - 31403, 0, 0},
+        // pmf: 1/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24,
+        // 2/24,
+        // 3/24
+        {32768 - 1365, 32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288,
+         32768 - 15019, 32768 - 17749, 32768 - 20480, 32768 - 23211,
+         32768 - 25941, 32768 - 28672, 0, 0},
+        // pmf: 1/24, 2/24, 2/24, 2/24, 2/24, 3/24, 3/24, 2/24, 2/24, 2/24,
+        // 2/24,
+        // 1/24
+        {32768 - 1365, 32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288,
+         32768 - 16384, 32768 - 20480, 32768 - 23211, 32768 - 25941,
+         32768 - 28672, 32768 - 31403, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 80; ++i) {
+      for (int j = 0; j < 24; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<12>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 12);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol12CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol12(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 80; ++i) {
+    for (int j = 0; j < 24; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol13(int num_runs) {
+  static constexpr int kSymbols[26][4] = {{0, 6, 12, 5},     //
+                                          {1, 7, 11, 4},     //
+                                          {2, 8, 10, 3},     //
+                                          {3, 9, 9, 2},      //
+                                          {4, 10, 8, 1},     //
+                                          {5, 11, 7, 0},     //
+                                          {6, 12, 6, 12},    //
+                                          {7, 0, 5, 11},     //
+                                          {8, 1, 4, 10},     //
+                                          {9, 2, 3, 9},      //
+                                          {10, 3, 2, 8},     //
+                                          {11, 4, 1, 7},     //
+                                          {12, 5, 0, 6},     //
+                                          {0, 0, 12, 11},    //
+                                          {2, 1, 10, 9},     //
+                                          {4, 3, 8, 7},      //
+                                          {6, 5, 6, 5},      //
+                                          {8, 7, 4, 3},      //
+                                          {10, 9, 2, 1},     //
+                                          {12, 11, 12, 10},  //
+                                          {1, 0, 11, 8},     //
+                                          {3, 2, 9, 6},      //
+                                          {5, 4, 7, 4},      //
+                                          {7, 6, 5, 2},      //
+                                          {9, 8, 3, 6},      //
+                                          {11, 10, 1, 6}};
+  absl::Duration elapsed_time;
+  int symbols[64 * 26 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol13, kNumBytesTestReadSymbol13,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][14] = {
+        // pmf: 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13,
+        // 1/13, 1/13, 1/13
+        {32768 - 2521, 32768 - 5041, 32768 - 7562, 32768 - 10082, 32768 - 12603,
+         32768 - 15124, 32768 - 17644, 32768 - 20165, 32768 - 22686,
+         32768 - 25206, 32768 - 27727, 32768 - 30247, 0, 0},
+        // pmf: 3/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26,
+        // 2/26, 2/26, 1/26
+        {32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343, 32768 - 13863,
+         32768 - 16384, 32768 - 18905, 32768 - 21425, 32768 - 23946,
+         32768 - 26466, 32768 - 28987, 32768 - 31508, 0, 0},
+        // pmf: 1/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26,
+        // 2/26, 2/26, 3/26
+        {32768 - 1260, 32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343,
+         32768 - 13863, 32768 - 16384, 32768 - 18905, 32768 - 21425,
+         32768 - 23946, 32768 - 26466, 32768 - 28987, 0, 0},
+        // pmf: 1/26, 2/26, 2/26, 2/26, 2/26, 2/26, 4/26, 2/26, 2/26, 2/26,
+        // 2/26, 2/26, 1/26
+        {32768 - 1260, 32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343,
+         32768 - 13863, 32768 - 18905, 32768 - 21425, 32768 - 23946,
+         32768 - 26466, 32768 - 28987, 32768 - 31508, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 64; ++i) {
+      for (int j = 0; j < 26; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<13>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 13);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol13CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol13(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 64; ++i) {
+    for (int j = 0; j < 26; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol14(int num_runs) {
+  static constexpr int kSymbols[28][4] = {{0, 7, 13, 6},    //
+                                          {1, 8, 12, 5},    //
+                                          {2, 9, 11, 4},    //
+                                          {3, 10, 10, 3},   //
+                                          {4, 11, 9, 2},    //
+                                          {5, 12, 8, 1},    //
+                                          {6, 13, 7, 0},    //
+                                          {7, 0, 6, 13},    //
+                                          {8, 1, 5, 12},    //
+                                          {9, 2, 4, 11},    //
+                                          {10, 3, 3, 10},   //
+                                          {11, 4, 2, 9},    //
+                                          {12, 5, 1, 8},    //
+                                          {13, 6, 0, 7},    //
+                                          {0, 0, 13, 11},   //
+                                          {2, 1, 12, 9},    //
+                                          {4, 3, 10, 7},    //
+                                          {6, 5, 8, 5},     //
+                                          {8, 7, 6, 3},     //
+                                          {10, 9, 4, 1},    //
+                                          {12, 11, 2, 12},  //
+                                          {1, 0, 13, 10},   //
+                                          {3, 2, 11, 8},    //
+                                          {5, 4, 9, 6},     //
+                                          {7, 6, 7, 4},     //
+                                          {9, 8, 5, 2},     //
+                                          {11, 10, 3, 7},   //
+                                          {13, 12, 1, 6}};
+  absl::Duration elapsed_time;
+  int symbols[64 * 28 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol14, kNumBytesTestReadSymbol14,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][15] = {
+        // pmf: 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14,
+        // 1/14, 1/14, 1/14, 1/14
+        {32768 - 2341, 32768 - 4681, 32768 - 7022, 32768 - 9362, 32768 - 11703,
+         32768 - 14043, 32768 - 16384, 32768 - 18725, 32768 - 21065,
+         32768 - 23406, 32768 - 25746, 32768 - 28087, 32768 - 30427, 0, 0},
+        // pmf: 3/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28,
+        // 2/28, 2/28, 2/28, 1/28
+        {32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533, 32768 - 12873,
+         32768 - 15214, 32768 - 17554, 32768 - 19895, 32768 - 22235,
+         32768 - 24576, 32768 - 26917, 32768 - 29257, 32768 - 31598, 0, 0},
+        // pmf: 1/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28,
+        // 2/28, 2/28, 2/28, 3/28
+        {32768 - 1170, 32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533,
+         32768 - 12873, 32768 - 15214, 32768 - 17554, 32768 - 19895,
+         32768 - 22235, 32768 - 24576, 32768 - 26917, 32768 - 29257, 0, 0},
+        // pmf: 1/28, 2/28, 2/28, 2/28, 2/28, 2/28, 3/28, 3/28, 2/28, 2/28,
+        // 2/28, 2/28, 2/28, 1/28
+        {32768 - 1170, 32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533,
+         32768 - 12873, 32768 - 16384, 32768 - 19895, 32768 - 22235,
+         32768 - 24576, 32768 - 26917, 32768 - 29257, 32768 - 31598, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 64; ++i) {
+      for (int j = 0; j < 28; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<14>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 14);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol14CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol14(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 64; ++i) {
+    for (int j = 0; j < 28; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+template <bool compile_time>
+void EntropyDecoderTest::TestReadSymbol16(int num_runs) {
+  static constexpr int kSymbols[32][4] = {{0, 8, 15, 7},    //
+                                          {1, 9, 14, 6},    //
+                                          {2, 10, 13, 5},   //
+                                          {3, 11, 12, 4},   //
+                                          {4, 12, 11, 3},   //
+                                          {5, 13, 10, 2},   //
+                                          {6, 14, 9, 1},    //
+                                          {7, 15, 8, 0},    //
+                                          {8, 0, 7, 15},    //
+                                          {9, 1, 6, 14},    //
+                                          {10, 2, 5, 13},   //
+                                          {11, 3, 4, 12},   //
+                                          {12, 4, 3, 11},   //
+                                          {13, 5, 2, 10},   //
+                                          {14, 6, 1, 9},    //
+                                          {15, 7, 0, 8},    //
+                                          {0, 0, 15, 13},   //
+                                          {2, 1, 14, 11},   //
+                                          {4, 3, 12, 9},    //
+                                          {6, 5, 10, 7},    //
+                                          {8, 7, 8, 5},     //
+                                          {10, 9, 6, 3},    //
+                                          {12, 11, 4, 1},   //
+                                          {14, 13, 2, 14},  //
+                                          {1, 0, 15, 12},   //
+                                          {3, 2, 13, 10},   //
+                                          {5, 4, 11, 8},    //
+                                          {7, 6, 9, 6},     //
+                                          {9, 8, 7, 4},     //
+                                          {11, 10, 5, 2},   //
+                                          {13, 12, 3, 8},   //
+                                          {15, 14, 1, 7}};
+  absl::Duration elapsed_time;
+  int symbols[48 * 32 * 4];
+  for (int run = 0; run < num_runs; ++run) {
+    EntropyDecoder reader(kBytesTestReadSymbol16, kNumBytesTestReadSymbol16,
+                          /*allow_update_cdf=*/true);
+    uint16_t cdf[4][17] = {
+        // pmf: 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16,
+        // 1/16, 1/16, 1/16, 1/16, 1/16, 1/16
+        {32768 - 2048, 32768 - 4096, 32768 - 6144, 32768 - 8192, 32768 - 10240,
+         32768 - 12288, 32768 - 14336, 32768 - 16384, 32768 - 18432,
+         32768 - 20480, 32768 - 22528, 32768 - 24576, 32768 - 26624,
+         32768 - 28672, 32768 - 30720, 0, 0},
+        // pmf: 3/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32,
+        // 2/32, 2/32, 2/32, 2/32, 2/32, 1/32
+        {32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216, 32768 - 11264,
+         32768 - 13312, 32768 - 15360, 32768 - 17408, 32768 - 19456,
+         32768 - 21504, 32768 - 23552, 32768 - 25600, 32768 - 27648,
+         32768 - 29696, 32768 - 31744, 0, 0},
+        // pmf: 1/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32,
+        // 2/32, 2/32, 2/32, 2/32, 2/32, 3/32
+        {32768 - 1024, 32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216,
+         32768 - 11264, 32768 - 13312, 32768 - 15360, 32768 - 17408,
+         32768 - 19456, 32768 - 21504, 32768 - 23552, 32768 - 25600,
+         32768 - 27648, 32768 - 29696, 0, 0},
+        // pmf: 1/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 3/32, 3/32, 2/32,
+        // 2/32, 2/32, 2/32, 2/32, 2/32, 1/32
+        {32768 - 1024, 32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216,
+         32768 - 11264, 32768 - 13312, 32768 - 16384, 32768 - 19456,
+         32768 - 21504, 32768 - 23552, 32768 - 25600, 32768 - 27648,
+         32768 - 29696, 32768 - 31744, 0, 0},
+    };
+    const absl::Time start = absl::Now();
+    int index = 0;
+    for (int i = 0; i < 48; ++i) {
+      for (int j = 0; j < 32; ++j) {
+        for (int k = 0; k < 4; ++k) {  // NOLINT(modernize-loop-convert)
+          if (compile_time) {
+            symbols[index++] = reader.ReadSymbol<16>(cdf[k]);
+          } else {
+            symbols[index++] = reader.ReadSymbol(cdf[k], 16);
+          }
+        }
+      }
+    }
+    elapsed_time += absl::Now() - start;
+  }
+  if (compile_time) {
+    printf("TestReadSymbol16CompileTime(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  } else {
+    printf("TestReadSymbol16(%d): %5d us\n", num_runs,
+           static_cast<int>(absl::ToInt64Microseconds(elapsed_time)));
+  }
+
+  int index = 0;
+  for (int i = 0; i < 48; ++i) {
+    for (int j = 0; j < 32; ++j) {  // NOLINT(modernize-loop-convert)
+      for (int k = 0; k < 4; ++k) {
+        ASSERT_EQ(symbols[index++], kSymbols[j][k]);
+      }
+    }
+  }
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbolBoolean) {
+  TestReadSymbolBoolean</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbolBooleanCompileTime) {
+  TestReadSymbolBoolean</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol3) {
+  TestReadSymbol3</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol3CompileTime) {
+  TestReadSymbol3</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol4) {
+  TestReadSymbol4</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol4CompileTime) {
+  TestReadSymbol4</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol5) {
+  TestReadSymbol5</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol5CompileTime) {
+  TestReadSymbol5</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol6) {
+  TestReadSymbol6</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol6CompileTime) {
+  TestReadSymbol6</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol7) {
+  TestReadSymbol7</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol7CompileTime) {
+  TestReadSymbol7</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol8) {
+  TestReadSymbol8</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol8CompileTime) {
+  TestReadSymbol8</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol9) {
+  TestReadSymbol9</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol9CompileTime) {
+  TestReadSymbol9</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol10) {
+  TestReadSymbol10</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol10CompileTime) {
+  TestReadSymbol10</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol11) {
+  TestReadSymbol11</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol11CompileTime) {
+  TestReadSymbol11</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol12) {
+  TestReadSymbol12</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol12CompileTime) {
+  TestReadSymbol12</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol13) {
+  TestReadSymbol13</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol13CompileTime) {
+  TestReadSymbol13</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol14) {
+  TestReadSymbol14</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol14CompileTime) {
+  TestReadSymbol14</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol16) {
+  TestReadSymbol16</*compile_time=*/false>(1);
+}
+
+TEST_F(EntropyDecoderTest, ReadSymbol16CompileTime) {
+  TestReadSymbol16</*compile_time=*/true>(1);
+}
+
+TEST_F(EntropyDecoderTest, DISABLED_Speed) {
+  // compile_time=true is only tested for those symbol_count values that have
+  // an instantiation of the EntropyDecoder::ReadSymbol<symbol_count> template
+  // method.
+  TestReadSymbolBoolean</*compile_time=*/false>(10000);
+  TestReadSymbolBoolean</*compile_time=*/true>(10000);
+  TestReadSymbol3</*compile_time=*/false>(5000);
+  TestReadSymbol3</*compile_time=*/true>(5000);
+  TestReadSymbol4</*compile_time=*/false>(2000);
+  TestReadSymbol4</*compile_time=*/true>(2000);
+  TestReadSymbol5</*compile_time=*/false>(5000);
+  TestReadSymbol5</*compile_time=*/true>(5000);
+  TestReadSymbol6</*compile_time=*/false>(5000);
+  TestReadSymbol6</*compile_time=*/true>(5000);
+  TestReadSymbol7</*compile_time=*/false>(1000);
+  TestReadSymbol7</*compile_time=*/true>(1000);
+  TestReadSymbol8</*compile_time=*/false>(1000);
+  TestReadSymbol8</*compile_time=*/true>(1000);
+  TestReadSymbol9</*compile_time=*/false>(5000);
+  TestReadSymbol9</*compile_time=*/true>(5000);
+  TestReadSymbol10</*compile_time=*/false>(5000);
+  TestReadSymbol10</*compile_time=*/true>(5000);
+  TestReadSymbol11</*compile_time=*/false>(5000);
+  TestReadSymbol11</*compile_time=*/true>(5000);
+  TestReadSymbol12</*compile_time=*/false>(5000);
+  TestReadSymbol12</*compile_time=*/true>(5000);
+  TestReadSymbol13</*compile_time=*/false>(5000);
+  TestReadSymbol13</*compile_time=*/true>(5000);
+  TestReadSymbol14</*compile_time=*/false>(5000);
+  TestReadSymbol14</*compile_time=*/true>(5000);
+  TestReadSymbol16</*compile_time=*/false>(5000);
+  TestReadSymbol16</*compile_time=*/true>(5000);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/entropy_decoder_test_data.inc b/src/utils/entropy_decoder_test_data.inc
new file mode 100644
index 0000000..9050d5e
--- /dev/null
+++ b/src/utils/entropy_decoder_test_data.inc
@@ -0,0 +1,8443 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The kBytesTestReadSymbolBoolean[] array was encoded by using the following
+// libaom code:
+//
+// aom_cdf_prob cdf[4][3] = {
+//   { 16384, 0, 0 },
+//   { 32768 - 8386, 0, 0 },
+//   { 32768 - 24312, 0, 0 },
+//   { 16384, 0, 0 },
+// };
+// constexpr int kSymbols[4][4] = { { 0, 0, 1, 1 },  //
+//                                  { 0, 1, 1, 0 },  //
+//                                  { 1, 0, 1, 0 },  //
+//                                  { 1, 0, 0, 1 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 1024; ++i) {
+//   for (int j = 0; j < 4; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 2);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("  constexpr size_t kNumBytesTestReadSymbolBoolean = %u;\n", bw.pos);
+// printf("  constexpr uint8_t kBytesTestReadSymbolBoolean[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n      ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n  };\n");
+
+constexpr size_t kNumBytesTestReadSymbolBoolean = 1880;
+constexpr uint8_t kBytesTestReadSymbolBoolean[] = {
+    0x1e, 0xfe, 0x7c, 0xa2, 0x1e, 0xfc, 0xa1, 0x17, 0xee, 0xbf, 0x07, 0x76,
+    0x2d, 0x11, 0x3a, 0xa5, 0x49, 0x65, 0xbb, 0x83, 0x89, 0x4b, 0xaa, 0x23,
+    0x29, 0x0d, 0x81, 0x9f, 0x6a, 0xf2, 0x9f, 0x7e, 0x14, 0x9a, 0x86, 0x78,
+    0x7f, 0xd5, 0x31, 0x14, 0x45, 0x8e, 0xf5, 0xc3, 0x36, 0x63, 0xcb, 0x4f,
+    0xeb, 0x81, 0x19, 0x75, 0x3c, 0xda, 0x21, 0x71, 0x1d, 0x05, 0x34, 0x7e,
+    0x43, 0xd4, 0x5b, 0xeb, 0x0a, 0x6d, 0xbe, 0xd2, 0x8f, 0xa5, 0x8f, 0xac,
+    0x3b, 0x43, 0xb6, 0x8a, 0xf9, 0x86, 0xf7, 0x1a, 0x3c, 0x4b, 0x2b, 0x4c,
+    0x4c, 0x4a, 0xff, 0xb9, 0x6f, 0x3c, 0xeb, 0xf6, 0x4c, 0xc8, 0x3c, 0x01,
+    0x5f, 0x12, 0x76, 0x4f, 0x88, 0xa0, 0xa5, 0xe7, 0x1d, 0xb3, 0x97, 0xd8,
+    0x31, 0x90, 0x8f, 0xd1, 0x46, 0xfd, 0xf7, 0xb1, 0x02, 0x0d, 0xf3, 0x9e,
+    0xbe, 0xa2, 0xfb, 0xc2, 0x7e, 0xe8, 0x77, 0xff, 0xa8, 0x13, 0x59, 0xcd,
+    0xba, 0xe7, 0xc2, 0x7e, 0xe8, 0x77, 0xff, 0xa8, 0x0e, 0xc3, 0x7b, 0x63,
+    0x80, 0xfe, 0x33, 0xe8, 0x30, 0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e,
+    0xbd, 0x33, 0xe8, 0x30, 0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd,
+    0x33, 0xe8, 0x30, 0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33,
+    0xe8, 0x30, 0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8,
+    0x30, 0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8, 0x30,
+    0x37, 0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8, 0x30, 0x37,
+    0xeb, 0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8, 0x30, 0x37, 0xeb,
+    0xd3, 0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8, 0x30, 0x37, 0xeb, 0xd3,
+    0x3e, 0x83, 0x03, 0x7e, 0xbd, 0x33, 0xe8, 0x30, 0x37, 0xeb, 0xd3, 0x3e,
+    0x85, 0x13, 0x83, 0xe9, 0x58, 0xaf, 0xe8, 0xff, 0x03, 0xb8, 0xf5, 0x08,
+    0x63, 0x03, 0xea, 0xe9, 0x3a, 0x39, 0x6d, 0xb6, 0x32, 0xc5, 0xff, 0xf7,
+    0x19, 0x19, 0x9c, 0x29, 0x3a, 0xc5, 0x87, 0x27, 0x2d, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13,
+    0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a,
+    0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf,
+    0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1,
+    0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89,
+    0x61, 0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61,
+    0x35, 0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35,
+    0xad, 0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad,
+    0xfa, 0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa,
+    0x18, 0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18,
+    0x96, 0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xad, 0xfa, 0x18, 0x96,
+    0x13, 0x5a, 0xdf, 0xa1, 0x89, 0x61, 0x35, 0xac,
+};
+static_assert(sizeof(kBytesTestReadSymbolBoolean) ==
+                  kNumBytesTestReadSymbolBoolean,
+              "");
+
+// The kBytesTestReadSymbol3[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][4] = {
+//   // pdf: 1/3, 1/3, 1/3
+//   { 32768 - 10923, 32768 - 21845, 0, 0 },
+//   // pdf: 1/6, 2/6, 3/6
+//   { 32768 - 5461, 32768 - 16384, 0, 0 },
+//   // pdf: 2/6, 3/6, 1/6
+//   { 32768 - 10923, 32768 - 27307, 0, 0 },
+//   // pdf: 3/6, 1/6, 2/6
+//   { 32768 - 16384, 32768 - 21845, 0, 0 },
+// };
+// constexpr int kSymbols[6][4] = { { 0, 2, 1, 2 },  //
+//                                  { 1, 1, 2, 1 },  //
+//                                  { 2, 0, 0, 0 },  //
+//                                  { 0, 2, 0, 2 },  //
+//                                  { 1, 2, 1, 0 },  //
+//                                  { 2, 1, 1, 0 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 1024; ++i) {
+//   for (int j = 0; j < 6; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 3);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("  constexpr size_t kNumBytesTestReadSymbol3 = %u;\n", bw.pos);
+// printf("  constexpr uint8_t kBytesTestReadSymbol3[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n      ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n  };\n");
+
+constexpr size_t kNumBytesTestReadSymbol3 = 4646;
+constexpr uint8_t kBytesTestReadSymbol3[] = {
+    0x4a, 0xf9, 0x1a, 0x00, 0xef, 0x80, 0xd4, 0xcd, 0xc2, 0x55, 0x62, 0x76,
+    0x3a, 0x60, 0x4e, 0xc9, 0x17, 0x91, 0x86, 0xb0, 0xa0, 0xcb, 0xf7, 0x7e,
+    0x82, 0x1e, 0x92, 0xd9, 0xe5, 0xff, 0xaa, 0x0b, 0xa4, 0xc1, 0xfa, 0x0d,
+    0xbe, 0x4f, 0x17, 0x4a, 0xfd, 0xee, 0xb6, 0x9b, 0x57, 0x3e, 0xdb, 0x60,
+    0x19, 0xd2, 0xee, 0x35, 0x39, 0x73, 0xc9, 0x7b, 0x80, 0xc0, 0x9c, 0x9a,
+    0xe8, 0x0f, 0x8b, 0xb8, 0x99, 0x02, 0xde, 0x68, 0x97, 0xab, 0xee, 0x2c,
+    0xa0, 0xb1, 0x7b, 0x8e, 0x8a, 0x69, 0xd5, 0xcd, 0x40, 0x43, 0xa9, 0x4c,
+    0xd5, 0xac, 0x33, 0x70, 0x64, 0x35, 0xa1, 0x18, 0xde, 0x31, 0x21, 0x2b,
+    0xa1, 0xd2, 0x87, 0x63, 0x41, 0x4d, 0xd9, 0x0e, 0x17, 0xd8, 0x74, 0x19,
+    0xbc, 0x33, 0xee, 0xd9, 0x21, 0x22, 0x16, 0xbb, 0x1e, 0x14, 0x46, 0xcf,
+    0xfa, 0xee, 0xa2, 0xa0, 0xc0, 0x6b, 0xc5, 0xf0, 0xd8, 0x23, 0x6d, 0x20,
+    0xda, 0x75, 0xff, 0x72, 0x3d, 0x41, 0x51, 0x21, 0x23, 0xa0, 0xce, 0xa0,
+    0x46, 0xb0, 0x1d, 0x3d, 0xaf, 0x64, 0xf8, 0x57, 0xee, 0x81, 0x55, 0x3a,
+    0xea, 0xd3, 0x3f, 0x96, 0x52, 0x31, 0xe5, 0xb5, 0x70, 0x01, 0x5a, 0xaf,
+    0xbc, 0x69, 0x7e, 0x43, 0xdd, 0x2f, 0xe2, 0x40, 0xc7, 0x2d, 0x62, 0x8e,
+    0xf0, 0x2a, 0xc0, 0x06, 0xe7, 0xe0, 0x63, 0x6e, 0x09, 0xa0, 0x57, 0x83,
+    0x43, 0x5a, 0xe8, 0xb5, 0xc7, 0x1b, 0xf5, 0xe6, 0x3d, 0x19, 0xeb, 0xfa,
+    0xda, 0x3d, 0x06, 0x3e, 0xa8, 0x96, 0x09, 0xad, 0x1d, 0xac, 0xf6, 0xef,
+    0xc7, 0x32, 0x2f, 0x45, 0xe0, 0x4f, 0xa6, 0x9c, 0x2f, 0x66, 0x6b, 0xe3,
+    0x36, 0xcf, 0x36, 0x41, 0xcb, 0xd9, 0xb8, 0xc3, 0x48, 0xf4, 0x18, 0xfa,
+    0xa2, 0x58, 0x26, 0xb4, 0x76, 0xb3, 0xdb, 0xbf, 0x1c, 0xc8, 0xbd, 0x19,
+    0xc1, 0x3e, 0x9a, 0x71, 0x85, 0x52, 0x94, 0x82, 0x48, 0x9c, 0x90, 0xcf,
+    0x2f, 0xa0, 0xd1, 0x4b, 0x73, 0xcf, 0x73, 0xea, 0x89, 0x60, 0x93, 0xd1,
+    0xda, 0xcf, 0x74, 0x5b, 0xd3, 0x22, 0xf4, 0x67, 0x04, 0xfa, 0x69, 0xc6,
+    0x15, 0x4a, 0x52, 0x09, 0x22, 0x72, 0x43, 0x3c, 0xbe, 0x83, 0x45, 0x2d,
+    0xcf, 0x3d, 0xcf, 0xaa, 0x25, 0x82, 0x4f, 0x47, 0x6b, 0x3d, 0xd1, 0x6f,
+    0x4c, 0x8b, 0xd1, 0x9c, 0x13, 0xe9, 0xa7, 0x18, 0x55, 0x29, 0x48, 0x24,
+    0x89, 0xc9, 0x0c, 0xf2, 0xfa, 0x0d, 0x14, 0xb7, 0x3c, 0xf7, 0x3e, 0xa8,
+    0x96, 0x09, 0x3d, 0x1d, 0xac, 0xf7, 0x45, 0xbd, 0x32, 0x2f, 0x46, 0x70,
+    0x4f, 0xa6, 0x9c, 0x61, 0x54, 0xa5, 0x20, 0x92, 0x27, 0x24, 0x33, 0xcb,
+    0xe8, 0x34, 0x52, 0xdc, 0xf3, 0xdc, 0xfa, 0xa2, 0x58, 0x24, 0xf4, 0x76,
+    0xb3, 0xdd, 0x16, 0xf4, 0xc8, 0xbd, 0x19, 0xc1, 0x3e, 0x9a, 0x71, 0x85,
+    0x52, 0x94, 0x82, 0x48, 0x9c, 0x90, 0xcf, 0x2f, 0xa0, 0xd1, 0x4b, 0x73,
+    0xcf, 0x73, 0xea, 0x89, 0x60, 0x93, 0xd1, 0xda, 0xcf, 0x74, 0x5b, 0xd3,
+    0x22, 0xf4, 0x67, 0x04, 0xfa, 0x69, 0xc6, 0x15, 0x4a, 0x52, 0x09, 0x22,
+    0x72, 0x43, 0x3c, 0xbe, 0x83, 0x45, 0x2d, 0xcf, 0x3d, 0xcf, 0xaa, 0x25,
+    0x84, 0xaa, 0xde, 0xde, 0xba, 0x7e, 0x90, 0x92, 0xa0, 0xdc, 0xb3, 0x6c,
+    0xaf, 0xe6, 0x2f, 0xeb, 0xc5, 0x33, 0xe7, 0x77, 0xcf, 0xda, 0xe7, 0x31,
+    0x57, 0xb2, 0x8f, 0xde, 0x8f, 0x1d, 0xf4, 0xd3, 0x8c, 0xda, 0x94, 0xa4,
+    0x12, 0xcd, 0xc9, 0x32, 0x6d, 0xf7, 0x2d, 0x0c, 0x2c, 0xf9, 0xd8, 0x0b,
+    0x48, 0xf3, 0xb3, 0x2e, 0x80, 0xd7, 0x0a, 0xc4, 0x4f, 0x09, 0xfe, 0x84,
+    0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4,
+    0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8,
+    0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a,
+    0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67,
+    0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09,
+    0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c,
+    0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef,
+    0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01,
+    0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35,
+    0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01,
+    0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8,
+    0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8,
+    0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54,
+    0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d,
+    0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0,
+    0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a,
+    0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52,
+    0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41,
+    0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b,
+    0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39,
+    0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09,
+    0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58,
+    0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d,
+    0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82,
+    0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad,
+    0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43,
+    0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7,
+    0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d,
+    0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f,
+    0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07,
+    0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65,
+    0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf,
+    0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78,
+    0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca,
+    0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9,
+    0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58,
+    0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8,
+    0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb,
+    0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d,
+    0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1,
+    0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06,
+    0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0,
+    0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56,
+    0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e,
+    0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10,
+    0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3,
+    0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60,
+    0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a,
+    0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f,
+    0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25,
+    0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3,
+    0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf,
+    0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07,
+    0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5,
+    0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04,
+    0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1,
+    0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3,
+    0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50,
+    0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5,
+    0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0,
+    0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8,
+    0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a,
+    0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04,
+    0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f,
+    0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5,
+    0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27,
+    0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60,
+    0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36,
+    0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a,
+    0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7,
+    0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c,
+    0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde,
+    0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75,
+    0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe,
+    0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d,
+    0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97,
+    0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc,
+    0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0,
+    0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b,
+    0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5,
+    0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63,
+    0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1,
+    0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d,
+    0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6,
+    0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06,
+    0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19,
+    0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2,
+    0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b,
+    0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb,
+    0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40,
+    0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d,
+    0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80,
+    0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa,
+    0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e,
+    0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95,
+    0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf,
+    0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc,
+    0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e,
+    0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54,
+    0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10,
+    0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86,
+    0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e,
+    0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42,
+    0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6,
+    0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03,
+    0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0,
+    0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b,
+    0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10,
+    0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd,
+    0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97,
+    0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f,
+    0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81,
+    0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9,
+    0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b,
+    0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde,
+    0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32,
+    0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a,
+    0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6,
+    0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa,
+    0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76,
+    0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f,
+    0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0,
+    0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81,
+    0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac,
+    0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95,
+    0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f,
+    0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84,
+    0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4,
+    0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8,
+    0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a,
+    0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67,
+    0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09,
+    0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c,
+    0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef,
+    0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01,
+    0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35,
+    0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01,
+    0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8,
+    0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8,
+    0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54,
+    0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d,
+    0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0,
+    0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a,
+    0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52,
+    0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41,
+    0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b,
+    0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39,
+    0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09,
+    0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58,
+    0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d,
+    0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82,
+    0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad,
+    0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43,
+    0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7,
+    0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d,
+    0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f,
+    0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07,
+    0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65,
+    0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf,
+    0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78,
+    0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca,
+    0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9,
+    0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58,
+    0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8,
+    0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb,
+    0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d,
+    0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1,
+    0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06,
+    0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0,
+    0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56,
+    0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e,
+    0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10,
+    0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3,
+    0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60,
+    0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a,
+    0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f,
+    0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25,
+    0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3,
+    0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf,
+    0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07,
+    0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5,
+    0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04,
+    0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1,
+    0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3,
+    0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50,
+    0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5,
+    0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0,
+    0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8,
+    0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a,
+    0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04,
+    0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f,
+    0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5,
+    0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27,
+    0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60,
+    0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36,
+    0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a,
+    0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7,
+    0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c,
+    0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde,
+    0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75,
+    0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe,
+    0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d,
+    0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97,
+    0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc,
+    0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0,
+    0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b,
+    0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5,
+    0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63,
+    0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1,
+    0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d,
+    0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6,
+    0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06,
+    0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19,
+    0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2,
+    0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b,
+    0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb,
+    0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40,
+    0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d,
+    0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80,
+    0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa,
+    0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e,
+    0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95,
+    0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf,
+    0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc,
+    0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e,
+    0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54,
+    0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10,
+    0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86,
+    0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e,
+    0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42,
+    0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6,
+    0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03,
+    0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0,
+    0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b,
+    0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10,
+    0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd,
+    0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97,
+    0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f,
+    0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81,
+    0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9,
+    0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b,
+    0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde,
+    0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32,
+    0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a,
+    0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6,
+    0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa,
+    0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76,
+    0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f,
+    0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0,
+    0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81,
+    0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac,
+    0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95,
+    0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f,
+    0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84,
+    0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4,
+    0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8,
+    0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a,
+    0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67,
+    0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09,
+    0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c,
+    0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef,
+    0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01,
+    0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35,
+    0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01,
+    0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8,
+    0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8,
+    0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54,
+    0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d,
+    0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0,
+    0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a,
+    0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52,
+    0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41,
+    0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b,
+    0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39,
+    0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09,
+    0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58,
+    0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d,
+    0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82,
+    0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad,
+    0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43,
+    0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7,
+    0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d,
+    0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f,
+    0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07,
+    0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65,
+    0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf,
+    0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78,
+    0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca,
+    0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9,
+    0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58,
+    0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8,
+    0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb,
+    0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d,
+    0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1,
+    0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06,
+    0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0,
+    0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56,
+    0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e,
+    0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10,
+    0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3,
+    0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60,
+    0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a,
+    0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f,
+    0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25,
+    0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3,
+    0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf,
+    0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07,
+    0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5,
+    0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04,
+    0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1,
+    0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3,
+    0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50,
+    0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5,
+    0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0,
+    0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8,
+    0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a,
+    0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04,
+    0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f,
+    0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5,
+    0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27,
+    0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60,
+    0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36,
+    0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a,
+    0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7,
+    0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c,
+    0xac, 0x25, 0x42, 0x7f, 0xa1, 0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde,
+    0x95, 0xb3, 0xd6, 0x07, 0x6d, 0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75,
+    0x8f, 0xbf, 0x03, 0x65, 0xf6, 0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe,
+    0x84, 0x07, 0xa0, 0xaf, 0x06, 0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d,
+    0xb4, 0xd5, 0x2b, 0x78, 0x19, 0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97,
+    0xd8, 0x04, 0x10, 0xca, 0xc2, 0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc,
+    0x1a, 0xa1, 0xbd, 0xe9, 0x5b, 0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0,
+    0x67, 0xe3, 0x97, 0x58, 0xfb, 0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b,
+    0x09, 0x50, 0x9f, 0xe8, 0x40, 0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5,
+    0x6c, 0xf5, 0x81, 0xdb, 0x4d, 0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63,
+    0xef, 0xc0, 0xd9, 0x7d, 0x80, 0x41, 0x0c, 0xac, 0x25, 0x42, 0x7f, 0xa1,
+    0x01, 0xe8, 0x2b, 0xc1, 0xaa, 0x1b, 0xde, 0x95, 0xb3, 0xd6, 0x07, 0x6d,
+    0x35, 0x4a, 0xde, 0x06, 0x7e, 0x39, 0x75, 0x8f, 0xbf, 0x03, 0x65, 0xf6,
+    0x01, 0x04, 0x32, 0xb0, 0x95, 0x09, 0xfe, 0x84, 0x07, 0xa0, 0xaf, 0x06,
+    0xa8, 0x6f, 0x7a, 0x56, 0xcf, 0x58, 0x1d, 0xb4, 0xd5, 0x2b, 0x78, 0x19,
+    0xf8, 0xe5, 0xd6, 0x3e, 0xfc, 0x0d, 0x97, 0xd8, 0x04, 0x10, 0xca, 0xc2,
+    0x54, 0x27, 0xfa, 0x10, 0x1e, 0x82, 0xbc, 0x1a, 0xa1, 0xbd, 0xe9, 0x5b,
+    0x3d, 0x60, 0x76, 0xd3, 0x54, 0xad, 0xe0, 0x67, 0xe3, 0x97, 0x58, 0xfb,
+    0xf0, 0x36, 0x5f, 0x60, 0x10, 0x43, 0x2b, 0x09, 0x50, 0x9f, 0xe8, 0x40,
+    0x7a, 0x0a, 0xf0, 0x6a, 0x86, 0xf7, 0xa5, 0x6c, 0xf5, 0x81, 0xdb, 0x4d,
+    0x52, 0xb7, 0x81, 0x9f, 0x8e, 0x5d, 0x63, 0xef, 0xc0, 0xd9, 0x7d, 0x80,
+    0x41, 0x08,
+};
+static_assert(sizeof(kBytesTestReadSymbol3) == kNumBytesTestReadSymbol3, "");
+
+// The kBytesTestReadSymbol4[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][5] = {
+//   // pdf: 1/4, 1/4, 1/4, 1/4
+//   { 32768 - 8192, 32768 - 16384, 32768 - 24576, 0, 0 },
+//   // pdf: 2/8, 1/8, 2/8, 3/8
+//   { 32768 - 8192, 32768 - 12288, 32768 - 20480, 0, 0 },
+//   // pdf: 1/4, 1/4, 1/4, 1/4
+//   { 32768 - 8192, 32768 - 16384, 32768 - 24576, 0, 0 },
+//   // pdf: 2/8, 3/8, 2/8, 1/8
+//   { 32768 - 8192, 32768 - 20480, 32768 - 28672, 0, 0 },
+// };
+// constexpr int kSymbols[8][4] = { { 0, 0, 3, 3 },  //
+//                                  { 0, 0, 2, 2 },  //
+//                                  { 1, 1, 0, 0 },  //
+//                                  { 1, 2, 1, 1 },  //
+//                                  { 2, 2, 3, 2 },  //
+//                                  { 2, 3, 2, 1 },  //
+//                                  { 3, 3, 0, 0 },  //
+//                                  { 3, 3, 1, 1 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 1024; ++i) {
+//   for (int j = 0; j < 8; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 4);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("  constexpr size_t kNumBytesTestReadSymbol4 = %u;\n", bw.pos);
+// printf("  constexpr uint8_t kBytesTestReadSymbol4[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n      ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n  };\n");
+
+constexpr size_t kNumBytesTestReadSymbol4 = 8055;
+constexpr uint8_t kBytesTestReadSymbol4[] = {
+    0x0f, 0x9b, 0x2a, 0xf6, 0x38, 0x26, 0xa1, 0xd1, 0x82, 0x5f, 0x34, 0xb5,
+    0xc7, 0xda, 0x9c, 0xd8, 0x8d, 0x4b, 0xbc, 0x5c, 0x0b, 0x8a, 0x7f, 0x6c,
+    0x46, 0x3f, 0xa2, 0x03, 0xee, 0x1f, 0xea, 0x25, 0xc7, 0xb7, 0xe2, 0xc9,
+    0x51, 0x0f, 0x7c, 0x0c, 0xe3, 0x7d, 0x7b, 0xe4, 0xbe, 0xde, 0x41, 0x5c,
+    0x5a, 0xcf, 0xe6, 0x12, 0x50, 0x7b, 0xcc, 0x83, 0x76, 0x61, 0x03, 0x3a,
+    0x1e, 0x1b, 0xf8, 0x9d, 0x08, 0x96, 0x98, 0x0f, 0x16, 0xac, 0x7c, 0x25,
+    0x6c, 0xd1, 0xe8, 0xd8, 0xd6, 0x1c, 0xbd, 0x48, 0xa5, 0x3f, 0xd3, 0x21,
+    0x4c, 0x4e, 0x94, 0xe3, 0xe3, 0xed, 0x30, 0x70, 0xdb, 0x2e, 0x95, 0xd5,
+    0x7f, 0xfe, 0xed, 0x0e, 0x73, 0xe3, 0x29, 0x09, 0x5f, 0xe3, 0x0e, 0xa6,
+    0xe7, 0xc6, 0x52, 0x12, 0xba, 0xdb, 0xb5, 0x63, 0xd9, 0xd8, 0xa4, 0x25,
+    0x75, 0xb7, 0x6a, 0xc7, 0xb3, 0xad, 0x88, 0x46, 0x64, 0x3a, 0x36, 0xb1,
+    0x2f, 0xb1, 0x03, 0xdb, 0x88, 0x74, 0x6d, 0x62, 0x5f, 0x62, 0x07, 0xb7,
+    0x10, 0xe8, 0xda, 0xc6, 0x1d, 0x6e, 0x8e, 0x12, 0x58, 0x6e, 0x98, 0x4c,
+    0xa1, 0x23, 0xc0, 0x9b, 0xb0, 0xdd, 0x31, 0xef, 0x64, 0xf0, 0x91, 0x37,
+    0x61, 0xba, 0x63, 0xde, 0xc9, 0xe1, 0x22, 0x6e, 0xc3, 0x74, 0xc7, 0xea,
+    0xcb, 0x70, 0xf6, 0xe2, 0x1d, 0x1b, 0x6c, 0xd5, 0x4f, 0x91, 0xc2, 0x4b,
+    0x0a, 0xeb, 0xb3, 0x0d, 0x59, 0x39, 0x13, 0x76, 0x15, 0xd7, 0x66, 0x1a,
+    0xf2, 0x72, 0x26, 0xec, 0x05, 0x3e, 0xcc, 0x31, 0x3e, 0x60, 0x4d, 0xd8,
+    0x0a, 0x7d, 0x98, 0x62, 0x7c, 0xc0, 0xcc, 0x5a, 0x24, 0xc8, 0xa6, 0xda,
+    0xe3, 0x09, 0x35, 0x70, 0x9c, 0x4c, 0x85, 0xac, 0x6f, 0x8b, 0x76, 0x30,
+    0xcc, 0x6f, 0xcb, 0x3e, 0x36, 0xd6, 0xec, 0x61, 0x98, 0xdf, 0x99, 0xa5,
+    0x7e, 0x2d, 0xd8, 0xc3, 0x31, 0xbf, 0x33, 0x4a, 0xfc, 0x5b, 0xb1, 0x86,
+    0x63, 0x7e, 0x66, 0x95, 0xf8, 0xb7, 0x63, 0x0c, 0xc6, 0xfc, 0xcd, 0x2b,
+    0xf1, 0x6e, 0xc6, 0x19, 0x8d, 0xf9, 0x9a, 0x57, 0xe2, 0xdd, 0x8c, 0x33,
+    0x1b, 0xf3, 0x34, 0xaf, 0xc5, 0xbb, 0x18, 0x66, 0x37, 0xe6, 0x69, 0x5f,
+    0x8b, 0x76, 0x30, 0xcc, 0x6f, 0xcc, 0xd2, 0xbf, 0x16, 0xec, 0x61, 0x98,
+    0xdf, 0x99, 0xa5, 0x7e, 0x2d, 0xd1, 0x27, 0xb1, 0xbf, 0x30, 0x0b, 0xfc,
+    0x5b, 0xa2, 0x4f, 0x63, 0xa0, 0x9b, 0x7a, 0xb6, 0xb7, 0x44, 0x9e, 0xc7,
+    0x41, 0x36, 0xf5, 0x6d, 0x6e, 0x89, 0x3d, 0x8e, 0x82, 0x6d, 0xea, 0xda,
+    0xdd, 0x12, 0x7b, 0x1d, 0x04, 0xdb, 0xd5, 0xb5, 0xba, 0x24, 0xf6, 0x3a,
+    0x09, 0xb7, 0xab, 0x6b, 0x74, 0x49, 0xec, 0x74, 0x13, 0x6f, 0x56, 0xd6,
+    0xe8, 0x93, 0xd8, 0xe8, 0x26, 0xde, 0xad, 0xad, 0xd1, 0x27, 0xb1, 0xd0,
+    0x4d, 0xbd, 0x5b, 0x5b, 0xa2, 0x4f, 0x63, 0xa0, 0x9b, 0x7a, 0xb6, 0xb7,
+    0x44, 0x9e, 0xc7, 0x41, 0x36, 0xf5, 0x6d, 0x6e, 0x89, 0x3d, 0x8e, 0x82,
+    0x6d, 0xea, 0xda, 0xdd, 0x12, 0x7b, 0x1d, 0x04, 0xdb, 0xd5, 0xb5, 0xba,
+    0x24, 0xf6, 0x3a, 0x09, 0xb7, 0xab, 0x6b, 0x74, 0x49, 0xec, 0x74, 0x13,
+    0x6f, 0x56, 0xd6, 0xdf, 0x45, 0xaa, 0x16, 0xb7, 0xb7, 0x14, 0x09, 0xdb,
+    0x9f, 0x17, 0x97, 0xae, 0xa1, 0xbe, 0x34, 0x9d, 0x0e, 0x01, 0x9f, 0xdb,
+    0x16, 0xa9, 0x6a, 0x63, 0xf2, 0x9f, 0x5b, 0x3b, 0x0b, 0xae, 0x17, 0xd6,
+    0x4d, 0x75, 0x8f, 0xe3, 0xf0, 0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c,
+    0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96,
+    0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f,
+    0x24, 0xa8, 0xcd, 0x3d, 0x44, 0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80,
+    0xc7, 0x1d, 0x6c, 0xec, 0xb3, 0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f,
+    0xfd, 0xba, 0x4e, 0x1a, 0xa5, 0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d,
+    0x7a, 0x15, 0x6d, 0x45, 0x02, 0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a,
+    0x7f, 0x3d, 0xe3, 0x6b, 0x55, 0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53,
+    0x8e, 0x9a, 0x82, 0x1c, 0x52, 0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91,
+    0xeb, 0x2c, 0x39, 0xb4, 0x7f, 0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9,
+    0xfe, 0xc6, 0x71, 0xd1, 0x81, 0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95,
+    0x19, 0xa7, 0xa8, 0x92, 0xf5, 0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3,
+    0xad, 0x9d, 0x96, 0x76, 0xfc, 0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7,
+    0x49, 0xc3, 0x54, 0xaa, 0xca, 0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42,
+    0xad, 0xa8, 0xa0, 0x4e, 0xdc, 0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7,
+    0xbc, 0x6d, 0x6a, 0xa9, 0x69, 0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3,
+    0x50, 0x43, 0x8a, 0x43, 0x70, 0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65,
+    0x87, 0x36, 0x8f, 0xec, 0x37, 0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8,
+    0xce, 0x3a, 0x30, 0x30, 0xf8, 0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34,
+    0xf5, 0x12, 0x5e, 0xb0, 0x1d, 0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3,
+    0xb2, 0xce, 0xdf, 0x80, 0x03, 0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38,
+    0x6a, 0x95, 0x59, 0x50, 0x0e, 0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5,
+    0x14, 0x09, 0xdb, 0x99, 0x9b, 0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d,
+    0xad, 0x55, 0x2d, 0x33, 0x71, 0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08,
+    0x71, 0x48, 0x6e, 0x13, 0x95, 0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6,
+    0xd1, 0xfd, 0x86, 0xef, 0xfc, 0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7,
+    0x46, 0x06, 0x1f, 0x05, 0x57, 0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2,
+    0x4b, 0xd6, 0x03, 0xa6, 0x15, 0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59,
+    0xdb, 0xf0, 0x00, 0x71, 0x1b, 0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52,
+    0xab, 0x2a, 0x01, 0xce, 0x12, 0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81,
+    0x3b, 0x73, 0x33, 0x61, 0x12, 0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa,
+    0xa5, 0xa6, 0x6e, 0x3e, 0xc2, 0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29,
+    0x0d, 0xc2, 0x72, 0xa9, 0x42, 0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f,
+    0xb0, 0xdd, 0xff, 0x8c, 0x99, 0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0,
+    0xc3, 0xe0, 0xaa, 0xf5, 0x68, 0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a,
+    0xc0, 0x74, 0xc2, 0xab, 0xa8, 0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e,
+    0x00, 0x0e, 0x23, 0x7f, 0x86, 0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65,
+    0x40, 0x39, 0xc2, 0x5e, 0xb4, 0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e,
+    0x66, 0x6c, 0x22, 0x44, 0xa7, 0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4,
+    0xcd, 0xc7, 0xd8, 0x53, 0xf5, 0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8,
+    0x4e, 0x55, 0x28, 0x59, 0x29, 0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b,
+    0xbf, 0xf1, 0x93, 0x2c, 0xde, 0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c,
+    0x15, 0x5e, 0xad, 0x1e, 0x49, 0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e,
+    0x98, 0x55, 0x75, 0x01, 0x8e, 0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01,
+    0xc4, 0x6f, 0xf0, 0xdf, 0xfb, 0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07,
+    0x38, 0x4b, 0xd6, 0x9a, 0xf4, 0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd,
+    0x84, 0x48, 0x94, 0xf4, 0xfe, 0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8,
+    0xfb, 0x0a, 0x7e, 0xa7, 0x1d, 0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca,
+    0xa5, 0x0b, 0x25, 0x23, 0xd6, 0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe,
+    0x32, 0x65, 0x9b, 0xd3, 0xfd, 0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab,
+    0xd5, 0xa3, 0xc9, 0x2a, 0x33, 0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a,
+    0xae, 0xa0, 0x31, 0xc7, 0x5b, 0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d,
+    0xfe, 0x1b, 0xff, 0x6e, 0x93, 0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09,
+    0x7a, 0xd3, 0x5e, 0x85, 0x5b, 0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89,
+    0x12, 0x9e, 0x9f, 0xcf, 0x78, 0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61,
+    0x4f, 0xd4, 0xe3, 0xa6, 0xa0, 0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1,
+    0x64, 0xa4, 0x7a, 0xcb, 0x0e, 0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c,
+    0xb3, 0x7a, 0x7f, 0xb1, 0x9c, 0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4,
+    0x79, 0x25, 0x46, 0x69, 0xea, 0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4,
+    0x06, 0x38, 0xeb, 0x67, 0x65, 0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3,
+    0x7f, 0xed, 0xd2, 0x70, 0xd5, 0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a,
+    0x6b, 0xd0, 0xab, 0x6a, 0x28, 0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53,
+    0xd3, 0xf9, 0xef, 0x1b, 0x5a, 0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa,
+    0x9c, 0x74, 0xd4, 0x10, 0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94,
+    0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f,
+    0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24,
+    0xa8, 0xcd, 0x3d, 0x44, 0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7,
+    0x1d, 0x6c, 0xec, 0xb3, 0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd,
+    0xba, 0x4e, 0x1a, 0xa5, 0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a,
+    0x15, 0x6d, 0x45, 0x02, 0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f,
+    0x3d, 0xe3, 0x6b, 0x55, 0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e,
+    0x9a, 0x82, 0x1c, 0x52, 0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb,
+    0x2c, 0x39, 0xb4, 0x7f, 0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe,
+    0xc6, 0x71, 0xd1, 0x81, 0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19,
+    0xa7, 0xa8, 0x92, 0xf5, 0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad,
+    0x9d, 0x96, 0x76, 0xfc, 0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49,
+    0xc3, 0x54, 0xaa, 0xca, 0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad,
+    0xa8, 0xa0, 0x4e, 0xdc, 0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc,
+    0x6d, 0x6a, 0xa9, 0x69, 0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50,
+    0x43, 0x8a, 0x43, 0x70, 0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87,
+    0x36, 0x8f, 0xec, 0x37, 0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce,
+    0x3a, 0x30, 0x30, 0xf8, 0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5,
+    0x12, 0x5e, 0xb0, 0x1d, 0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2,
+    0xce, 0xdf, 0x80, 0x03, 0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a,
+    0x95, 0x59, 0x50, 0x0e, 0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14,
+    0x09, 0xdb, 0x99, 0x9b, 0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad,
+    0x55, 0x2d, 0x33, 0x71, 0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71,
+    0x48, 0x6e, 0x13, 0x95, 0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1,
+    0xfd, 0x86, 0xef, 0xfc, 0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46,
+    0x06, 0x1f, 0x05, 0x57, 0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b,
+    0xd6, 0x03, 0xa6, 0x15, 0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb,
+    0xf0, 0x00, 0x71, 0x1b, 0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab,
+    0x2a, 0x01, 0xce, 0x12, 0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b,
+    0x73, 0x33, 0x61, 0x12, 0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5,
+    0xa6, 0x6e, 0x3e, 0xc2, 0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d,
+    0xc2, 0x72, 0xa9, 0x42, 0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0,
+    0xdd, 0xff, 0x8c, 0x99, 0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3,
+    0xe0, 0xaa, 0xf5, 0x68, 0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0,
+    0x74, 0xc2, 0xab, 0xa8, 0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00,
+    0x0e, 0x23, 0x7f, 0x86, 0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40,
+    0x39, 0xc2, 0x5e, 0xb4, 0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66,
+    0x6c, 0x22, 0x44, 0xa7, 0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd,
+    0xc7, 0xd8, 0x53, 0xf5, 0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e,
+    0x55, 0x28, 0x59, 0x29, 0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf,
+    0xf1, 0x93, 0x2c, 0xde, 0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15,
+    0x5e, 0xad, 0x1e, 0x49, 0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98,
+    0x55, 0x75, 0x01, 0x8e, 0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4,
+    0x6f, 0xf0, 0xdf, 0xfb, 0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38,
+    0x4b, 0xd6, 0x9a, 0xf4, 0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84,
+    0x48, 0x94, 0xf4, 0xfe, 0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb,
+    0x0a, 0x7e, 0xa7, 0x1d, 0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5,
+    0x0b, 0x25, 0x23, 0xd6, 0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32,
+    0x65, 0x9b, 0xd3, 0xfd, 0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5,
+    0xa3, 0xc9, 0x2a, 0x33, 0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae,
+    0xa0, 0x31, 0xc7, 0x5b, 0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe,
+    0x1b, 0xff, 0x6e, 0x93, 0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a,
+    0xd3, 0x5e, 0x85, 0x5b, 0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12,
+    0x9e, 0x9f, 0xcf, 0x78, 0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f,
+    0xd4, 0xe3, 0xa6, 0xa0, 0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64,
+    0xa4, 0x7a, 0xcb, 0x0e, 0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3,
+    0x7a, 0x7f, 0xb1, 0x9c, 0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79,
+    0x25, 0x46, 0x69, 0xea, 0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06,
+    0x38, 0xeb, 0x67, 0x65, 0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f,
+    0xed, 0xd2, 0x70, 0xd5, 0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b,
+    0xd0, 0xab, 0x6a, 0x28, 0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3,
+    0xf9, 0xef, 0x1b, 0x5a, 0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c,
+    0x74, 0xd4, 0x10, 0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f,
+    0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f,
+    0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8,
+    0xcd, 0x3d, 0x44, 0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d,
+    0x6c, 0xec, 0xb3, 0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba,
+    0x4e, 0x1a, 0xa5, 0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15,
+    0x6d, 0x45, 0x02, 0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d,
+    0xe3, 0x6b, 0x55, 0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a,
+    0x82, 0x1c, 0x52, 0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c,
+    0x39, 0xb4, 0x7f, 0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6,
+    0x71, 0xd1, 0x81, 0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7,
+    0xa8, 0x92, 0xf5, 0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d,
+    0x96, 0x76, 0xfc, 0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3,
+    0x54, 0xaa, 0xca, 0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8,
+    0xa0, 0x4e, 0xdc, 0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d,
+    0x6a, 0xa9, 0x69, 0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43,
+    0x8a, 0x43, 0x70, 0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36,
+    0x8f, 0xec, 0x37, 0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a,
+    0x30, 0x30, 0xf8, 0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12,
+    0x5e, 0xb0, 0x1d, 0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce,
+    0xdf, 0x80, 0x03, 0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95,
+    0x59, 0x50, 0x0e, 0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09,
+    0xdb, 0x99, 0x9b, 0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55,
+    0x2d, 0x33, 0x71, 0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48,
+    0x6e, 0x13, 0x95, 0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd,
+    0x86, 0xef, 0xfc, 0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06,
+    0x1f, 0x05, 0x57, 0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6,
+    0x03, 0xa6, 0x15, 0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0,
+    0x00, 0x71, 0x1b, 0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a,
+    0x01, 0xce, 0x12, 0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73,
+    0x33, 0x61, 0x12, 0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6,
+    0x6e, 0x3e, 0xc2, 0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2,
+    0x72, 0xa9, 0x42, 0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd,
+    0xff, 0x8c, 0x99, 0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0,
+    0xaa, 0xf5, 0x68, 0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74,
+    0xc2, 0xab, 0xa8, 0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e,
+    0x23, 0x7f, 0x86, 0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39,
+    0xc2, 0x5e, 0xb4, 0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c,
+    0x22, 0x44, 0xa7, 0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7,
+    0xd8, 0x53, 0xf5, 0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55,
+    0x28, 0x59, 0x29, 0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1,
+    0x93, 0x2c, 0xde, 0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e,
+    0xad, 0x1e, 0x49, 0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55,
+    0x75, 0x01, 0x8e, 0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f,
+    0xf0, 0xdf, 0xfb, 0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b,
+    0xd6, 0x9a, 0xf4, 0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48,
+    0x94, 0xf4, 0xfe, 0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a,
+    0x7e, 0xa7, 0x1d, 0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b,
+    0x25, 0x23, 0xd6, 0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65,
+    0x9b, 0xd3, 0xfd, 0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3,
+    0xc9, 0x2a, 0x33, 0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0,
+    0x31, 0xc7, 0x5b, 0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b,
+    0xff, 0x6e, 0x93, 0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3,
+    0x5e, 0x85, 0x5b, 0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e,
+    0x9f, 0xcf, 0x78, 0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4,
+    0xe3, 0xa6, 0xa0, 0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4,
+    0x7a, 0xcb, 0x0e, 0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a,
+    0x7f, 0xb1, 0x9c, 0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25,
+    0x46, 0x69, 0xea, 0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38,
+    0xeb, 0x67, 0x65, 0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed,
+    0xd2, 0x70, 0xd5, 0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0,
+    0xab, 0x6a, 0x28, 0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9,
+    0xef, 0x1b, 0x5a, 0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74,
+    0xd4, 0x10, 0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59,
+    0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6,
+    0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd,
+    0x3d, 0x44, 0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c,
+    0xec, 0xb3, 0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e,
+    0x1a, 0xa5, 0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d,
+    0x45, 0x02, 0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3,
+    0x6b, 0x55, 0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82,
+    0x1c, 0x52, 0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39,
+    0xb4, 0x7f, 0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71,
+    0xd1, 0x81, 0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8,
+    0x92, 0xf5, 0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96,
+    0x76, 0xfc, 0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54,
+    0xaa, 0xca, 0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0,
+    0x4e, 0xdc, 0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a,
+    0xa9, 0x69, 0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a,
+    0x43, 0x70, 0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f,
+    0xec, 0x37, 0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30,
+    0x30, 0xf8, 0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e,
+    0xb0, 0x1d, 0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf,
+    0x80, 0x03, 0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59,
+    0x50, 0x0e, 0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb,
+    0x99, 0x9b, 0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d,
+    0x33, 0x71, 0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e,
+    0x13, 0x95, 0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86,
+    0xef, 0xfc, 0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f,
+    0x05, 0x57, 0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03,
+    0xa6, 0x15, 0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00,
+    0x71, 0x1b, 0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01,
+    0xce, 0x12, 0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33,
+    0x61, 0x12, 0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e,
+    0x3e, 0xc2, 0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72,
+    0xa9, 0x42, 0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff,
+    0x8c, 0x99, 0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa,
+    0xf5, 0x68, 0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2,
+    0xab, 0xa8, 0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23,
+    0x7f, 0x86, 0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2,
+    0x5e, 0xb4, 0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22,
+    0x44, 0xa7, 0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8,
+    0x53, 0xf5, 0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28,
+    0x59, 0x29, 0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93,
+    0x2c, 0xde, 0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad,
+    0x1e, 0x49, 0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75,
+    0x01, 0x8e, 0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0,
+    0xdf, 0xfb, 0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6,
+    0x9a, 0xf4, 0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94,
+    0xf4, 0xfe, 0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e,
+    0xa7, 0x1d, 0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25,
+    0x23, 0xd6, 0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b,
+    0xd3, 0xfd, 0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9,
+    0x2a, 0x33, 0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31,
+    0xc7, 0x5b, 0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff,
+    0x6e, 0x93, 0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e,
+    0x85, 0x5b, 0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f,
+    0xcf, 0x78, 0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3,
+    0xa6, 0xa0, 0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a,
+    0xcb, 0x0e, 0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f,
+    0xb1, 0x9c, 0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46,
+    0x69, 0xea, 0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb,
+    0x67, 0x65, 0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2,
+    0x70, 0xd5, 0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab,
+    0x6a, 0x28, 0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef,
+    0x1b, 0x5a, 0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4,
+    0x10, 0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61,
+    0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33,
+    0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d,
+    0x44, 0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec,
+    0xb3, 0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a,
+    0xa5, 0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45,
+    0x02, 0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b,
+    0x55, 0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c,
+    0x52, 0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4,
+    0x7f, 0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1,
+    0x81, 0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92,
+    0xf5, 0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76,
+    0xfc, 0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa,
+    0xca, 0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e,
+    0xdc, 0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9,
+    0x69, 0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43,
+    0x70, 0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec,
+    0x37, 0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30,
+    0xf8, 0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0,
+    0x1d, 0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80,
+    0x03, 0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50,
+    0x0e, 0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99,
+    0x9b, 0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33,
+    0x71, 0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13,
+    0x95, 0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef,
+    0xfc, 0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05,
+    0x57, 0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6,
+    0x15, 0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71,
+    0x1b, 0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce,
+    0x12, 0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61,
+    0x12, 0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e,
+    0xc2, 0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9,
+    0x42, 0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c,
+    0x99, 0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5,
+    0x68, 0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab,
+    0xa8, 0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f,
+    0x86, 0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e,
+    0xb4, 0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44,
+    0xa7, 0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53,
+    0xf5, 0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59,
+    0x29, 0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c,
+    0xde, 0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e,
+    0x49, 0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01,
+    0x8e, 0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf,
+    0xfb, 0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a,
+    0xf4, 0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4,
+    0xfe, 0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7,
+    0x1d, 0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23,
+    0xd6, 0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3,
+    0xfd, 0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a,
+    0x33, 0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7,
+    0x5b, 0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e,
+    0x93, 0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85,
+    0x5b, 0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf,
+    0x78, 0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6,
+    0xa0, 0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb,
+    0x0e, 0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1,
+    0x9c, 0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69,
+    0xea, 0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67,
+    0x65, 0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70,
+    0xd5, 0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a,
+    0x28, 0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b,
+    0x5a, 0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10,
+    0xe2, 0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd,
+    0xa3, 0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e,
+    0x8c, 0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d, 0x44,
+    0x97, 0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec, 0xb3,
+    0xb7, 0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a, 0xa5,
+    0x56, 0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45, 0x02,
+    0x76, 0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b, 0x55,
+    0x4b, 0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c, 0x52,
+    0x1b, 0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4, 0x7f,
+    0x61, 0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1, 0x81,
+    0x87, 0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92, 0xf5,
+    0x80, 0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76, 0xfc,
+    0x00, 0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa, 0xca,
+    0x80, 0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e, 0xdc,
+    0xcc, 0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9, 0x69,
+    0x9b, 0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43, 0x70,
+    0x9c, 0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec, 0x37,
+    0x7f, 0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30, 0xf8,
+    0x2a, 0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0, 0x1d,
+    0x30, 0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80, 0x03,
+    0x88, 0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50, 0x0e,
+    0x70, 0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99, 0x9b,
+    0x08, 0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33, 0x71,
+    0xf6, 0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13, 0x95,
+    0x4a, 0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef, 0xfc,
+    0x64, 0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05, 0x57,
+    0xab, 0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6, 0x15,
+    0x5d, 0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71, 0x1b,
+    0xfc, 0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce, 0x12,
+    0xf5, 0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61, 0x12,
+    0x25, 0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e, 0xc2,
+    0x9f, 0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9, 0x42,
+    0xc9, 0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c, 0x99,
+    0x66, 0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5, 0x68,
+    0xf2, 0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab, 0xa8,
+    0x0c, 0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f, 0x86,
+    0xff, 0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e, 0xb4,
+    0xd7, 0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44, 0xa7,
+    0xa7, 0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53, 0xf5,
+    0x38, 0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59, 0x29,
+    0x1e, 0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c, 0xde,
+    0x9f, 0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e, 0x49,
+    0x51, 0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01, 0x8e,
+    0x3a, 0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf, 0xfb,
+    0x74, 0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a, 0xf4,
+    0x2a, 0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4, 0xfe,
+    0x7b, 0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7, 0x1d,
+    0x35, 0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23, 0xd6,
+    0x58, 0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3, 0xfd,
+    0x8c, 0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a, 0x33,
+    0x4f, 0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7, 0x5b,
+    0x3b, 0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e, 0x93,
+    0x86, 0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85, 0x5b,
+    0x51, 0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf, 0x78,
+    0xda, 0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6, 0xa0,
+    0x87, 0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb, 0x0e,
+    0x6d, 0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1, 0x9c,
+    0x74, 0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69, 0xea,
+    0x24, 0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67, 0x65,
+    0x9d, 0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70, 0xd5,
+    0x2a, 0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a, 0x28,
+    0x13, 0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b, 0x5a,
+    0xaa, 0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10, 0xe2,
+    0x90, 0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3,
+    0xfb, 0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c,
+    0x0c, 0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d, 0x44, 0x97,
+    0xac, 0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec, 0xb3, 0xb7,
+    0xe0, 0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a, 0xa5, 0x56,
+    0x54, 0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45, 0x02, 0x76,
+    0xe6, 0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b, 0x55, 0x4b,
+    0x4c, 0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c, 0x52, 0x1b,
+    0x84, 0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4, 0x7f, 0x61,
+    0xbb, 0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1, 0x81, 0x87,
+    0xc1, 0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92, 0xf5, 0x80,
+    0xe9, 0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76, 0xfc, 0x00,
+    0x1c, 0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa, 0xca, 0x80,
+    0x73, 0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e, 0xdc, 0xcc,
+    0xd8, 0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9, 0x69, 0x9b,
+    0x8f, 0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43, 0x70, 0x9c,
+    0xaa, 0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec, 0x37, 0x7f,
+    0xe3, 0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30, 0xf8, 0x2a,
+    0xbd, 0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0, 0x1d, 0x30,
+    0xaa, 0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80, 0x03, 0x88,
+    0xdf, 0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50, 0x0e, 0x70,
+    0x97, 0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99, 0x9b, 0x08,
+    0x91, 0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33, 0x71, 0xf6,
+    0x14, 0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13, 0x95, 0x4a,
+    0x16, 0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef, 0xfc, 0x64,
+    0xcb, 0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05, 0x57, 0xab,
+    0x47, 0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6, 0x15, 0x5d,
+    0x40, 0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71, 0x1b, 0xfc,
+    0x37, 0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce, 0x12, 0xf5,
+    0xa6, 0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61, 0x12, 0x25,
+    0x3d, 0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e, 0xc2, 0x9f,
+    0xa9, 0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9, 0x42, 0xc9,
+    0x48, 0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c, 0x99, 0x66,
+    0xf4, 0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5, 0x68, 0xf2,
+    0x4a, 0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab, 0xa8, 0x0c,
+    0x71, 0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f, 0x86, 0xff,
+    0xdb, 0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e, 0xb4, 0xd7,
+    0xa1, 0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44, 0xa7, 0xa7,
+    0xf3, 0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53, 0xf5, 0x38,
+    0xe9, 0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59, 0x29, 0x1e,
+    0xb2, 0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c, 0xde, 0x9f,
+    0xec, 0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e, 0x49, 0x51,
+    0x9a, 0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01, 0x8e, 0x3a,
+    0xd9, 0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf, 0xfb, 0x74,
+    0x9c, 0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a, 0xf4, 0x2a,
+    0xda, 0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4, 0xfe, 0x7b,
+    0xc6, 0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7, 0x1d, 0x35,
+    0x04, 0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23, 0xd6, 0x58,
+    0x73, 0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3, 0xfd, 0x8c,
+    0xe3, 0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a, 0x33, 0x4f,
+    0x51, 0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7, 0x5b, 0x3b,
+    0x2c, 0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e, 0x93, 0x86,
+    0xa9, 0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85, 0x5b, 0x51,
+    0x40, 0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf, 0x78, 0xda,
+    0xd5, 0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6, 0xa0, 0x87,
+    0x14, 0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb, 0x0e, 0x6d,
+    0x1f, 0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1, 0x9c, 0x74,
+    0x60, 0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69, 0xea, 0x24,
+    0xbd, 0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67, 0x65, 0x9d,
+    0xbf, 0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70, 0xd5, 0x2a,
+    0xb2, 0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a, 0x28, 0x13,
+    0xb7, 0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b, 0x5a, 0xaa,
+    0x5a, 0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10, 0xe2, 0x90,
+    0xdc, 0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb,
+    0x0d, 0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c,
+    0x3e, 0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d, 0x44, 0x97, 0xac,
+    0x07, 0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec, 0xb3, 0xb7, 0xe0,
+    0x00, 0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a, 0xa5, 0x56, 0x54,
+    0x03, 0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45, 0x02, 0x76, 0xe6,
+    0x66, 0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b, 0x55, 0x4b, 0x4c,
+    0xdc, 0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c, 0x52, 0x1b, 0x84,
+    0xe5, 0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4, 0x7f, 0x61, 0xbb,
+    0xff, 0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1, 0x81, 0x87, 0xc1,
+    0x55, 0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92, 0xf5, 0x80, 0xe9,
+    0x85, 0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76, 0xfc, 0x00, 0x1c,
+    0x46, 0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa, 0xca, 0x80, 0x73,
+    0x84, 0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e, 0xdc, 0xcc, 0xd8,
+    0x44, 0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9, 0x69, 0x9b, 0x8f,
+    0xb0, 0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43, 0x70, 0x9c, 0xaa,
+    0x50, 0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec, 0x37, 0x7f, 0xe3,
+    0x26, 0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30, 0xf8, 0x2a, 0xbd,
+    0x5a, 0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0, 0x1d, 0x30, 0xaa,
+    0xea, 0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80, 0x03, 0x88, 0xdf,
+    0xe1, 0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50, 0x0e, 0x70, 0x97,
+    0xad, 0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99, 0x9b, 0x08, 0x91,
+    0x29, 0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33, 0x71, 0xf6, 0x14,
+    0xfd, 0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13, 0x95, 0x4a, 0x16,
+    0x4a, 0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef, 0xfc, 0x64, 0xcb,
+    0x37, 0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05, 0x57, 0xab, 0x47,
+    0x92, 0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6, 0x15, 0x5d, 0x40,
+    0x63, 0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71, 0x1b, 0xfc, 0x37,
+    0xfe, 0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce, 0x12, 0xf5, 0xa6,
+    0xbd, 0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61, 0x12, 0x25, 0x3d,
+    0x3f, 0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e, 0xc2, 0x9f, 0xa9,
+    0xc7, 0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9, 0x42, 0xc9, 0x48,
+    0xf5, 0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c, 0x99, 0x66, 0xf4,
+    0xff, 0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5, 0x68, 0xf2, 0x4a,
+    0x8c, 0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab, 0xa8, 0x0c, 0x71,
+    0xd6, 0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f, 0x86, 0xff, 0xdb,
+    0xa4, 0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e, 0xb4, 0xd7, 0xa1,
+    0x56, 0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44, 0xa7, 0xa7, 0xf3,
+    0xde, 0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53, 0xf5, 0x38, 0xe9,
+    0xa8, 0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59, 0x29, 0x1e, 0xb2,
+    0xc3, 0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c, 0xde, 0x9f, 0xec,
+    0x67, 0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e, 0x49, 0x51, 0x9a,
+    0x7a, 0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01, 0x8e, 0x3a, 0xd9,
+    0xd9, 0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf, 0xfb, 0x74, 0x9c,
+    0x35, 0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a, 0xf4, 0x2a, 0xda,
+    0x8a, 0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4, 0xfe, 0x7b, 0xc6,
+    0xd6, 0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7, 0x1d, 0x35, 0x04,
+    0x38, 0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23, 0xd6, 0x58, 0x73,
+    0x68, 0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3, 0xfd, 0x8c, 0xe3,
+    0xa3, 0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a, 0x33, 0x4f, 0x51,
+    0x25, 0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7, 0x5b, 0x3b, 0x2c,
+    0xed, 0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e, 0x93, 0x86, 0xa9,
+    0x55, 0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85, 0x5b, 0x51, 0x40,
+    0x9d, 0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf, 0x78, 0xda, 0xd5,
+    0x52, 0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6, 0xa0, 0x87, 0x14,
+    0x86, 0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb, 0x0e, 0x6d, 0x1f,
+    0xd8, 0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1, 0x9c, 0x74, 0x60,
+    0x61, 0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69, 0xea, 0x24, 0xbd,
+    0x60, 0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67, 0x65, 0x9d, 0xbf,
+    0x00, 0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70, 0xd5, 0x2a, 0xb2,
+    0xa0, 0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a, 0x28, 0x13, 0xb7,
+    0x33, 0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b, 0x5a, 0xaa, 0x5a,
+    0x66, 0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10, 0xe2, 0x90, 0xdc,
+    0x27, 0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d,
+    0xdf, 0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e,
+    0x0a, 0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d, 0x44, 0x97, 0xac, 0x07,
+    0x4c, 0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec, 0xb3, 0xb7, 0xe0, 0x00,
+    0xe2, 0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a, 0xa5, 0x56, 0x54, 0x03,
+    0x9c, 0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45, 0x02, 0x76, 0xe6, 0x66,
+    0xc2, 0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b, 0x55, 0x4b, 0x4c, 0xdc,
+    0x7d, 0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c, 0x52, 0x1b, 0x84, 0xe5,
+    0x52, 0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4, 0x7f, 0x61, 0xbb, 0xff,
+    0x19, 0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1, 0x81, 0x87, 0xc1, 0x55,
+    0xea, 0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92, 0xf5, 0x80, 0xe9, 0x85,
+    0x57, 0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76, 0xfc, 0x00, 0x1c, 0x46,
+    0xff, 0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa, 0xca, 0x80, 0x73, 0x84,
+    0xbd, 0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e, 0xdc, 0xcc, 0xd8, 0x44,
+    0x89, 0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9, 0x69, 0x9b, 0x8f, 0xb0,
+    0xa7, 0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43, 0x70, 0x9c, 0xaa, 0x50,
+    0xb2, 0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec, 0x37, 0x7f, 0xe3, 0x26,
+    0x59, 0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30, 0xf8, 0x2a, 0xbd, 0x5a,
+    0x3c, 0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0, 0x1d, 0x30, 0xaa, 0xea,
+    0x03, 0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80, 0x03, 0x88, 0xdf, 0xe1,
+    0xbf, 0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50, 0x0e, 0x70, 0x97, 0xad,
+    0x35, 0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99, 0x9b, 0x08, 0x91, 0x29,
+    0xe9, 0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33, 0x71, 0xf6, 0x14, 0xfd,
+    0x4e, 0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13, 0x95, 0x4a, 0x16, 0x4a,
+    0x47, 0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef, 0xfc, 0x64, 0xcb, 0x37,
+    0xa7, 0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05, 0x57, 0xab, 0x47, 0x92,
+    0x54, 0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6, 0x15, 0x5d, 0x40, 0x63,
+    0x8e, 0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71, 0x1b, 0xfc, 0x37, 0xfe,
+    0xdd, 0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce, 0x12, 0xf5, 0xa6, 0xbd,
+    0x0a, 0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61, 0x12, 0x25, 0x3d, 0x3f,
+    0x9e, 0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e, 0xc2, 0x9f, 0xa9, 0xc7,
+    0x4d, 0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9, 0x42, 0xc9, 0x48, 0xf5,
+    0x96, 0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c, 0x99, 0x66, 0xf4, 0xff,
+    0x63, 0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5, 0x68, 0xf2, 0x4a, 0x8c,
+    0xd3, 0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab, 0xa8, 0x0c, 0x71, 0xd6,
+    0xce, 0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f, 0x86, 0xff, 0xdb, 0xa4,
+    0xe1, 0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e, 0xb4, 0xd7, 0xa1, 0x56,
+    0xd4, 0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44, 0xa7, 0xa7, 0xf3, 0xde,
+    0x36, 0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53, 0xf5, 0x38, 0xe9, 0xa8,
+    0x21, 0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59, 0x29, 0x1e, 0xb2, 0xc3,
+    0x9b, 0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c, 0xde, 0x9f, 0xec, 0x67,
+    0x1d, 0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e, 0x49, 0x51, 0x9a, 0x7a,
+    0x89, 0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01, 0x8e, 0x3a, 0xd9, 0xd9,
+    0x67, 0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf, 0xfb, 0x74, 0x9c, 0x35,
+    0x4a, 0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a, 0xf4, 0x2a, 0xda, 0x8a,
+    0x04, 0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4, 0xfe, 0x7b, 0xc6, 0xd6,
+    0xaa, 0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7, 0x1d, 0x35, 0x04, 0x38,
+    0xa4, 0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23, 0xd6, 0x58, 0x73, 0x68,
+    0xfe, 0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3, 0xfd, 0x8c, 0xe3, 0xa3,
+    0x03, 0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a, 0x33, 0x4f, 0x51, 0x25,
+    0xeb, 0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7, 0x5b, 0x3b, 0x2c, 0xed,
+    0xf8, 0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e, 0x93, 0x86, 0xa9, 0x55,
+    0x95, 0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85, 0x5b, 0x51, 0x40, 0x9d,
+    0xb9, 0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf, 0x78, 0xda, 0xd5, 0x52,
+    0xd3, 0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6, 0xa0, 0x87, 0x14, 0x86,
+    0xe1, 0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb, 0x0e, 0x6d, 0x1f, 0xd8,
+    0x6e, 0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1, 0x9c, 0x74, 0x60, 0x61,
+    0xf0, 0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69, 0xea, 0x24, 0xbd, 0x60,
+    0x3a, 0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67, 0x65, 0x9d, 0xbf, 0x00,
+    0x07, 0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70, 0xd5, 0x2a, 0xb2, 0xa0,
+    0x1c, 0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a, 0x28, 0x13, 0xb7, 0x33,
+    0x36, 0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b, 0x5a, 0xaa, 0x5a, 0x66,
+    0xe3, 0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10, 0xe2, 0x90, 0xdc, 0x27,
+    0x2a, 0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf,
+    0xf8, 0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a,
+    0xaf, 0x56, 0x8f, 0x24, 0xa8, 0xcd, 0x3d, 0x44, 0x97, 0xac, 0x07, 0x4c,
+    0x2a, 0xba, 0x80, 0xc7, 0x1d, 0x6c, 0xec, 0xb3, 0xb7, 0xe0, 0x00, 0xe2,
+    0x37, 0xf8, 0x6f, 0xfd, 0xba, 0x4e, 0x1a, 0xa5, 0x56, 0x54, 0x03, 0x9c,
+    0x25, 0xeb, 0x4d, 0x7a, 0x15, 0x6d, 0x45, 0x02, 0x76, 0xe6, 0x66, 0xc2,
+    0x24, 0x4a, 0x7a, 0x7f, 0x3d, 0xe3, 0x6b, 0x55, 0x4b, 0x4c, 0xdc, 0x7d,
+    0x85, 0x3f, 0x53, 0x8e, 0x9a, 0x82, 0x1c, 0x52, 0x1b, 0x84, 0xe5, 0x52,
+    0x85, 0x92, 0x91, 0xeb, 0x2c, 0x39, 0xb4, 0x7f, 0x61, 0xbb, 0xff, 0x19,
+    0x32, 0xcd, 0xe9, 0xfe, 0xc6, 0x71, 0xd1, 0x81, 0x87, 0xc1, 0x55, 0xea,
+    0xd1, 0xe4, 0x95, 0x19, 0xa7, 0xa8, 0x92, 0xf5, 0x80, 0xe9, 0x85, 0x57,
+    0x50, 0x18, 0xe3, 0xad, 0x9d, 0x96, 0x76, 0xfc, 0x00, 0x1c, 0x46, 0xff,
+    0x0d, 0xff, 0xb7, 0x49, 0xc3, 0x54, 0xaa, 0xca, 0x80, 0x73, 0x84, 0xbd,
+    0x69, 0xaf, 0x42, 0xad, 0xa8, 0xa0, 0x4e, 0xdc, 0xcc, 0xd8, 0x44, 0x89,
+    0x4f, 0x4f, 0xe7, 0xbc, 0x6d, 0x6a, 0xa9, 0x69, 0x9b, 0x8f, 0xb0, 0xa7,
+    0xea, 0x71, 0xd3, 0x50, 0x43, 0x8a, 0x43, 0x70, 0x9c, 0xaa, 0x50, 0xb2,
+    0x52, 0x3d, 0x65, 0x87, 0x36, 0x8f, 0xec, 0x37, 0x7f, 0xe3, 0x26, 0x59,
+    0xbd, 0x3f, 0xd8, 0xce, 0x3a, 0x30, 0x30, 0xf8, 0x2a, 0xbd, 0x5a, 0x3c,
+    0x92, 0xa3, 0x34, 0xf5, 0x12, 0x5e, 0xb0, 0x1d, 0x30, 0xaa, 0xea, 0x03,
+    0x1c, 0x75, 0xb3, 0xb2, 0xce, 0xdf, 0x80, 0x03, 0x88, 0xdf, 0xe1, 0xbf,
+    0xf6, 0xe9, 0x38, 0x6a, 0x95, 0x59, 0x50, 0x0e, 0x70, 0x97, 0xad, 0x35,
+    0xe8, 0x55, 0xb5, 0x14, 0x09, 0xdb, 0x99, 0x9b, 0x08, 0x91, 0x29, 0xe9,
+    0xfc, 0xf7, 0x8d, 0xad, 0x55, 0x2d, 0x33, 0x71, 0xf6, 0x14, 0xfd, 0x4e,
+    0x3a, 0x6a, 0x08, 0x71, 0x48, 0x6e, 0x13, 0x95, 0x4a, 0x16, 0x4a, 0x47,
+    0xac, 0xb0, 0xe6, 0xd1, 0xfd, 0x86, 0xef, 0xfc, 0x64, 0xcb, 0x37, 0xa7,
+    0xfb, 0x19, 0xc7, 0x46, 0x06, 0x1f, 0x05, 0x57, 0xab, 0x47, 0x92, 0x54,
+    0x66, 0x9e, 0xa2, 0x4b, 0xd6, 0x03, 0xa6, 0x15, 0x5d, 0x40, 0x63, 0x8e,
+    0xb6, 0x76, 0x59, 0xdb, 0xf0, 0x00, 0x71, 0x1b, 0xfc, 0x37, 0xfe, 0xdd,
+    0x27, 0x0d, 0x52, 0xab, 0x2a, 0x01, 0xce, 0x12, 0xf5, 0xa6, 0xbd, 0x0a,
+    0xb6, 0xa2, 0x81, 0x3b, 0x73, 0x33, 0x61, 0x12, 0x25, 0x3d, 0x3f, 0x9e,
+    0xf1, 0xb5, 0xaa, 0xa5, 0xa6, 0x6e, 0x3e, 0xc2, 0x9f, 0xa9, 0xc7, 0x4d,
+    0x41, 0x0e, 0x29, 0x0d, 0xc2, 0x72, 0xa9, 0x42, 0xc9, 0x48, 0xf5, 0x96,
+    0x1c, 0xda, 0x3f, 0xb0, 0xdd, 0xff, 0x8c, 0x99, 0x66, 0xf4, 0xff, 0x63,
+    0x38, 0xe8, 0xc0, 0xc3, 0xe0, 0xaa, 0xf5, 0x68, 0xf2, 0x4a, 0x8c, 0xd3,
+    0xd4, 0x49, 0x7a, 0xc0, 0x74, 0xc2, 0xab, 0xa8, 0x0c, 0x71, 0xd6, 0xce,
+    0xcb, 0x3b, 0x7e, 0x00, 0x0e, 0x23, 0x7f, 0x86, 0xff, 0xdb, 0xa4, 0xe1,
+    0xaa, 0x55, 0x65, 0x40, 0x39, 0xc2, 0x5e, 0xb4, 0xd7, 0xa1, 0x56, 0xd4,
+    0x50, 0x27, 0x6e, 0x66, 0x6c, 0x22, 0x44, 0xa7, 0xa7, 0xf3, 0xde, 0x36,
+    0xb5, 0x54, 0xb4, 0xcd, 0xc7, 0xd8, 0x53, 0xf5, 0x38, 0xe9, 0xa8, 0x21,
+    0xc5, 0x21, 0xb8, 0x4e, 0x55, 0x28, 0x59, 0x29, 0x1e, 0xb2, 0xc3, 0x9b,
+    0x47, 0xf6, 0x1b, 0xbf, 0xf1, 0x93, 0x2c, 0xde, 0x9f, 0xec, 0x67, 0x1d,
+    0x18, 0x18, 0x7c, 0x15, 0x5e, 0xad, 0x1e, 0x49, 0x51, 0x9a, 0x7a, 0x89,
+    0x2f, 0x58, 0x0e, 0x98, 0x55, 0x75, 0x01, 0x8e, 0x3a, 0xd9, 0xd9, 0x67,
+    0x6f, 0xc0, 0x01, 0xc4, 0x6f, 0xf0, 0xdf, 0xfb, 0x74, 0x9c, 0x35, 0x4a,
+    0xac, 0xa8, 0x07, 0x38, 0x4b, 0xd6, 0x9a, 0xf4, 0x2a, 0xda, 0x8a, 0x04,
+    0xed, 0xcc, 0xcd, 0x84, 0x48, 0x94, 0xf4, 0xfe, 0x7b, 0xc6, 0xd6, 0xaa,
+    0x96, 0x99, 0xb8, 0xfb, 0x0a, 0x7e, 0xa7, 0x1d, 0x35, 0x04, 0x38, 0xa4,
+    0x37, 0x09, 0xca, 0xa5, 0x0b, 0x25, 0x23, 0xd6, 0x58, 0x73, 0x68, 0xfe,
+    0xc3, 0x77, 0xfe, 0x32, 0x65, 0x9b, 0xd3, 0xfd, 0x8c, 0xe3, 0xa3, 0x03,
+    0x0f, 0x82, 0xab, 0xd5, 0xa3, 0xc9, 0x2a, 0x33, 0x4f, 0x51, 0x25, 0xeb,
+    0x01, 0xd3, 0x0a, 0xae, 0xa0, 0x31, 0xc7, 0x5b, 0x3b, 0x2c, 0xed, 0xf8,
+    0x00, 0x38, 0x8d, 0xfe, 0x1b, 0xff, 0x6e, 0x93, 0x86, 0xa9, 0x55, 0x95,
+    0x00, 0xe7, 0x09, 0x7a, 0xd3, 0x5e, 0x85, 0x5b, 0x51, 0x40, 0x9d, 0xb9,
+    0x99, 0xb0, 0x89, 0x12, 0x9e, 0x9f, 0xcf, 0x78, 0xda, 0xd5, 0x52, 0xd3,
+    0x37, 0x1f, 0x61, 0x4f, 0xd4, 0xe3, 0xa6, 0xa0, 0x87, 0x14, 0x86, 0xe1,
+    0x39, 0x54, 0xa1, 0x64, 0xa4, 0x7a, 0xcb, 0x0e, 0x6d, 0x1f, 0xd8, 0x6e,
+    0xff, 0xc6, 0x4c, 0xb3, 0x7a, 0x7f, 0xb1, 0x9c, 0x74, 0x60, 0x61, 0xf0,
+    0x55, 0x7a, 0xb4, 0x79, 0x25, 0x46, 0x69, 0xea, 0x24, 0xbd, 0x60, 0x3a,
+    0x61, 0x55, 0xd4, 0x06, 0x38, 0xeb, 0x67, 0x65, 0x9d, 0xbf, 0x00, 0x07,
+    0x11, 0xbf, 0xc3, 0x7f, 0xed, 0xd2, 0x70, 0xd5, 0x2a, 0xb2, 0xa0, 0x1c,
+    0xe1, 0x2f, 0x5a, 0x6b, 0xd0, 0xab, 0x6a, 0x28, 0x13, 0xb7, 0x33, 0x36,
+    0x11, 0x22, 0x53, 0xd3, 0xf9, 0xef, 0x1b, 0x5a, 0xaa, 0x5a, 0x66, 0xe3,
+    0xec, 0x29, 0xfa, 0x9c, 0x74, 0xd4, 0x10, 0xe2, 0x90, 0xdc, 0x27, 0x2a,
+    0x94, 0x2c, 0x94, 0x8f, 0x59, 0x61, 0xcd, 0xa3, 0xfb, 0x0d, 0xdf, 0xf8,
+    0xc9, 0x96, 0x6f, 0x4f, 0xf6, 0x33, 0x8e, 0x8c, 0x0c, 0x3e, 0x0a, 0xaf,
+    0x56, 0x8f, 0x24,
+};
+static_assert(sizeof(kBytesTestReadSymbol4) == kNumBytesTestReadSymbol4, "");
+
+// The kBytesTestReadSymbol5[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][6] = {
+//   // pdf: 1/5, 1/5, 1/5, 1/5, 1/5
+//   { 32768 - 6554, 32768 - 13107, 32768 - 19661, 32768 - 26214, 0, 0 },
+//   // pdf: 3/10, 2/10, 2/10, 2/10, 1/10
+//   { 32768 - 9830, 32768 - 16384, 32768 - 22938, 32768 - 29491, 0, 0 },
+//   // pdf: 1/10, 2/10, 2/10, 2/10, 3/10
+//   { 32768 - 3277, 32768 - 9830, 32768 - 16384, 32768 - 22938, 0, 0 },
+//   // pdf: 1/10, 2/10, 4/10, 2/10, 1/10
+//   { 32768 - 3277, 32768 - 9830, 32768 - 22938, 32768 - 29491, 0, 0 },
+// };
+// constexpr int kSymbols[10][4] = { { 0, 0, 4, 4 },  //
+//                                   { 0, 1, 3, 3 },  //
+//                                   { 1, 2, 2, 2 },  //
+//                                   { 1, 3, 1, 1 },  //
+//                                   { 2, 4, 0, 0 },  //
+//                                   { 2, 0, 4, 3 },  //
+//                                   { 3, 1, 3, 2 },  //
+//                                   { 3, 2, 2, 1 },  //
+//                                   { 4, 3, 1, 2 },  //
+//                                   { 4, 0, 4, 2 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 320; ++i) {
+//   for (int j = 0; j < 10; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 5);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol5 = 3612;
+constexpr uint8_t kBytesTestReadSymbol5[] = {
+    0x0f, 0x1c, 0x16, 0x78, 0x6f, 0x83, 0xfe, 0x29, 0x95, 0x9a, 0x42, 0xcc,
+    0x70, 0x9a, 0x0d, 0x72, 0xe0, 0x7d, 0x63, 0x9e, 0x05, 0x3c, 0x88, 0x22,
+    0x40, 0x57, 0x83, 0xa8, 0x69, 0x6f, 0xc3, 0xb2, 0x58, 0x6c, 0xa9, 0x41,
+    0x3c, 0x2f, 0x3f, 0xa3, 0xe6, 0x4e, 0x5e, 0xaf, 0x42, 0x56, 0x9d, 0x3f,
+    0x70, 0xeb, 0x00, 0x02, 0x86, 0x23, 0x5f, 0x8e, 0x1b, 0x35, 0x71, 0x7d,
+    0x50, 0xbe, 0xb1, 0x1e, 0xe9, 0x2f, 0x08, 0x5a, 0x04, 0xc0, 0x7b, 0x98,
+    0x20, 0xbd, 0xc5, 0x39, 0xf7, 0x93, 0x5c, 0x6c, 0x4a, 0x0f, 0x50, 0x24,
+    0xe1, 0xf3, 0x2a, 0x8d, 0x53, 0x55, 0x9a, 0xd6, 0x3a, 0xd3, 0xd6, 0x9c,
+    0x41, 0xa2, 0x2c, 0x05, 0x1c, 0x5a, 0x28, 0x8d, 0xc0, 0x4f, 0x8d, 0xc1,
+    0x40, 0xaa, 0x19, 0xbf, 0xa7, 0x93, 0x48, 0xdf, 0x54, 0xcf, 0xb4, 0x47,
+    0xc4, 0x39, 0x90, 0xbb, 0xff, 0xb4, 0x47, 0x65, 0x33, 0x34, 0x45, 0x23,
+    0x5e, 0x79, 0xc5, 0xbd, 0x24, 0x30, 0x58, 0x8a, 0x19, 0x68, 0xbb, 0x08,
+    0xaa, 0xff, 0xce, 0x68, 0x37, 0xb4, 0x62, 0x44, 0x31, 0xe8, 0x3e, 0x4d,
+    0x05, 0x1d, 0xe2, 0x48, 0x56, 0xd5, 0x53, 0x19, 0xcc, 0xfd, 0x82, 0xa7,
+    0x06, 0xc4, 0x66, 0x95, 0x6c, 0x43, 0x3d, 0x43, 0x86, 0xe3, 0x62, 0x51,
+    0x26, 0x1c, 0x57, 0xed, 0x9a, 0x1a, 0x14, 0x4f, 0x41, 0x96, 0xc0, 0x72,
+    0x38, 0x59, 0xff, 0x69, 0xae, 0x2b, 0x59, 0x65, 0x30, 0xfd, 0xa5, 0x6f,
+    0x1b, 0xab, 0x01, 0x72, 0xb4, 0xcd, 0xba, 0x44, 0x73, 0x12, 0x31, 0xee,
+    0x83, 0x08, 0x5c, 0x35, 0x41, 0x17, 0xf1, 0x80, 0x55, 0xdd, 0x67, 0xb2,
+    0xd3, 0xe1, 0x04, 0x51, 0x69, 0x9b, 0x4b, 0x98, 0xcf, 0x17, 0x0a, 0xd4,
+    0xdc, 0x61, 0xf2, 0xb9, 0x4b, 0x23, 0xb6, 0xe8, 0x0c, 0x0d, 0xda, 0x68,
+    0xac, 0xd9, 0xf4, 0x11, 0x63, 0x4a, 0x7f, 0x17, 0x69, 0xdb, 0x91, 0x1b,
+    0x1d, 0xfb, 0x74, 0x58, 0x69, 0xcc, 0xf5, 0xce, 0x0d, 0x1e, 0xdd, 0x6d,
+    0x2e, 0x87, 0xf2, 0x36, 0x39, 0x22, 0x59, 0x78, 0x01, 0x2c, 0xf0, 0xe6,
+    0x8c, 0xd1, 0xdb, 0xa4, 0xf4, 0xc4, 0x09, 0x0e, 0xfe, 0x93, 0x88, 0x90,
+    0x3e, 0x55, 0x60, 0x51, 0x6a, 0xe9, 0x26, 0x41, 0x1f, 0x18, 0xab, 0xc1,
+    0xa4, 0x66, 0x57, 0xdd, 0xe6, 0x88, 0xbd, 0x74, 0xa0, 0xd3, 0x65, 0x0d,
+    0x04, 0xe3, 0x97, 0x1e, 0x9b, 0x59, 0xfc, 0xe2, 0x45, 0x9b, 0x90, 0xe1,
+    0x80, 0x20, 0x85, 0x03, 0x06, 0x1f, 0x46, 0xb1, 0x69, 0xb4, 0xf3, 0x06,
+    0xa8, 0xb5, 0x78, 0x2c, 0x21, 0xd1, 0x67, 0x8d, 0x91, 0xef, 0x6f, 0xec,
+    0xed, 0x2c, 0xd7, 0x40, 0x32, 0x09, 0xed, 0x4e, 0x92, 0xbb, 0x28, 0x67,
+    0xac, 0x09, 0x50, 0x7f, 0x30, 0xed, 0xde, 0x56, 0xeb, 0xc9, 0x23, 0x2f,
+    0x13, 0x07, 0xef, 0x80, 0x9e, 0x83, 0x6a, 0x24, 0xd4, 0xd1, 0x84, 0xbe,
+    0xf8, 0x1f, 0xb0, 0xaa, 0x6a, 0xf0, 0xda, 0x02, 0x0c, 0x94, 0xc9, 0xbc,
+    0x0f, 0xe8, 0x76, 0x95, 0x79, 0x0e, 0x24, 0x1e, 0x4c, 0xdb, 0xe5, 0xd5,
+    0x20, 0xee, 0x13, 0xff, 0xba, 0x1f, 0x7f, 0x67, 0x89, 0x4b, 0x6b, 0x28,
+    0x33, 0x61, 0xfb, 0x53, 0xed, 0xf7, 0x13, 0x3f, 0x64, 0xc9, 0x26, 0x19,
+    0xde, 0xe6, 0xec, 0x74, 0xe0, 0x0e, 0x7b, 0x07, 0xeb, 0xd9, 0xac, 0x7e,
+    0x1d, 0xac, 0xba, 0xa0, 0x50, 0xc4, 0x12, 0xee, 0x58, 0xe5, 0xe9, 0x7c,
+    0xa3, 0x40, 0xbd, 0x92, 0x6d, 0xa8, 0x08, 0x3c, 0x9e, 0xdb, 0xd3, 0x08,
+    0x3d, 0xb3, 0x1c, 0x25, 0x09, 0x51, 0x55, 0xbb, 0x51, 0xc8, 0xe6, 0xd6,
+    0x30, 0x86, 0x25, 0xa9, 0x01, 0xed, 0x55, 0x11, 0xa4, 0x5e, 0x3f, 0x57,
+    0xb7, 0x9b, 0x64, 0xec, 0x3d, 0x93, 0x28, 0x34, 0xea, 0xe9, 0x53, 0xec,
+    0x71, 0x7c, 0x1c, 0xee, 0x03, 0x26, 0x1a, 0x15, 0x9f, 0x6c, 0x74, 0xa5,
+    0xe1, 0x04, 0x76, 0xcb, 0x0b, 0xf9, 0x96, 0x4f, 0x4e, 0xb6, 0x7e, 0xad,
+    0xc5, 0x4b, 0x37, 0x44, 0x91, 0xfd, 0x1d, 0x69, 0x11, 0x17, 0x82, 0xc4,
+    0x17, 0x39, 0x29, 0x99, 0x8f, 0xe1, 0x35, 0x4d, 0x9e, 0x4f, 0xc9, 0x98,
+    0x71, 0x6b, 0xa9, 0x0d, 0x0a, 0xf8, 0xb6, 0x3a, 0x52, 0xf0, 0x82, 0x3b,
+    0x65, 0x79, 0x60, 0x16, 0xa5, 0xa4, 0xf8, 0x0e, 0xc2, 0x3e, 0xf3, 0x23,
+    0x82, 0x4d, 0x1f, 0x9d, 0x7b, 0xe1, 0xb8, 0xd3, 0x79, 0xc4, 0x04, 0x1d,
+    0xfc, 0xbc, 0xdb, 0x37, 0x73, 0x27, 0xe3, 0x8d, 0x65, 0xcb, 0x72, 0xd2,
+    0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x13, 0x0d, 0x80, 0xf6, 0xaa, 0x90,
+    0xd2, 0x30, 0x87, 0x1b, 0xdb, 0xcd, 0xb9, 0xea, 0x28, 0xfa, 0x10, 0xd5,
+    0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b, 0x6d, 0x42, 0x15, 0xc2, 0xf4,
+    0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5, 0xb9, 0x69, 0x57, 0xf2, 0x3d,
+    0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc, 0x90, 0x8e, 0xc9, 0x18, 0x43,
+    0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55, 0x08, 0x6a, 0xf8, 0x79, 0xd9,
+    0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a, 0xe1, 0x7a, 0x62, 0x93, 0xdc,
+    0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab, 0xf9, 0x1e, 0xa6, 0xf1, 0x75,
+    0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64, 0x8c, 0x21, 0xc6, 0xf6, 0xf2,
+    0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c, 0x3c, 0xec, 0xc9, 0xad, 0x4a,
+    0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31, 0x49, 0xee, 0x30, 0x68, 0xe5,
+    0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53, 0x78, 0xba, 0xe0, 0x2c, 0x34,
+    0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3, 0x7b, 0x79, 0x25, 0x39, 0xba,
+    0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64, 0xd6, 0xa5, 0x69, 0x6d, 0xa8,
+    0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18, 0x34, 0x72, 0xbc, 0xb7, 0x2d,
+    0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70, 0x16, 0x1a, 0x59, 0x92, 0x11,
+    0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92, 0x9c, 0xdd, 0x2a, 0xa1, 0x0d,
+    0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4, 0xb6, 0xd4, 0x21, 0x5c, 0x2f,
+    0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e, 0x5b, 0x96, 0x95, 0x7f, 0x23,
+    0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c, 0xc9, 0x08, 0xec, 0x91, 0x84,
+    0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95, 0x50, 0x86, 0xaf, 0x87, 0x9d,
+    0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10, 0xae, 0x17, 0xa6, 0x29, 0x3d,
+    0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a, 0xbf, 0x91, 0xea, 0x6f, 0x17,
+    0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76, 0x48, 0xc2, 0x1c, 0x6f, 0x6f,
+    0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57, 0xc3, 0xce, 0xcc, 0x9a, 0xd4,
+    0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3, 0x14, 0x9e, 0xe3, 0x06, 0x8e,
+    0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5, 0x37, 0x8b, 0xae, 0x02, 0xc3,
+    0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e, 0x37, 0xb7, 0x92, 0x53, 0x9b,
+    0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66, 0x4d, 0x6a, 0x56, 0x96, 0xda,
+    0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71, 0x83, 0x47, 0x2b, 0xcb, 0x72,
+    0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x01, 0x61, 0xa5, 0x99, 0x21,
+    0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9, 0x29, 0xcd, 0xd2, 0xaa, 0x10,
+    0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b, 0x6d, 0x42, 0x15, 0xc2,
+    0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5, 0xb9, 0x69, 0x57, 0xf2,
+    0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc, 0x90, 0x8e, 0xc9, 0x18,
+    0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55, 0x08, 0x6a, 0xf8, 0x79,
+    0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a, 0xe1, 0x7a, 0x62, 0x93,
+    0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab, 0xf9, 0x1e, 0xa6, 0xf1,
+    0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64, 0x8c, 0x21, 0xc6, 0xf6,
+    0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c, 0x3c, 0xec, 0xc9, 0xad,
+    0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31, 0x49, 0xee, 0x30, 0x68,
+    0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53, 0x78, 0xba, 0xe0, 0x2c,
+    0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3, 0x7b, 0x79, 0x25, 0x39,
+    0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64, 0xd6, 0xa5, 0x69, 0x6d,
+    0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18, 0x34, 0x72, 0xbc, 0xb7,
+    0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70, 0x16, 0x1a, 0x59, 0x92,
+    0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92, 0x9c, 0xdd, 0x2a, 0xa1,
+    0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4, 0xb6, 0xd4, 0x21, 0x5c,
+    0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e, 0x5b, 0x96, 0x95, 0x7f,
+    0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c, 0xc9, 0x08, 0xec, 0x91,
+    0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95, 0x50, 0x86, 0xaf, 0x87,
+    0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10, 0xae, 0x17, 0xa6, 0x29,
+    0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a, 0xbf, 0x91, 0xea, 0x6f,
+    0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76, 0x48, 0xc2, 0x1c, 0x6f,
+    0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57, 0xc3, 0xce, 0xcc, 0x9a,
+    0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3, 0x14, 0x9e, 0xe3, 0x06,
+    0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5, 0x37, 0x8b, 0xae, 0x02,
+    0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e, 0x37, 0xb7, 0x92, 0x53,
+    0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66, 0x4d, 0x6a, 0x56, 0x96,
+    0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71, 0x83, 0x47, 0x2b, 0xcb,
+    0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x01, 0x61, 0xa5, 0x99,
+    0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9, 0x29, 0xcd, 0xd2, 0xaa,
+    0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b, 0x6d, 0x42, 0x15,
+    0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5, 0xb9, 0x69, 0x57,
+    0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc, 0x90, 0x8e, 0xc9,
+    0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55, 0x08, 0x6a, 0xf8,
+    0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a, 0xe1, 0x7a, 0x62,
+    0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab, 0xf9, 0x1e, 0xa6,
+    0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64, 0x8c, 0x21, 0xc6,
+    0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c, 0x3c, 0xec, 0xc9,
+    0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31, 0x49, 0xee, 0x30,
+    0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53, 0x78, 0xba, 0xe0,
+    0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3, 0x7b, 0x79, 0x25,
+    0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64, 0xd6, 0xa5, 0x69,
+    0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18, 0x34, 0x72, 0xbc,
+    0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70, 0x16, 0x1a, 0x59,
+    0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92, 0x9c, 0xdd, 0x2a,
+    0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4, 0xb6, 0xd4, 0x21,
+    0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e, 0x5b, 0x96, 0x95,
+    0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c, 0xc9, 0x08, 0xec,
+    0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95, 0x50, 0x86, 0xaf,
+    0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10, 0xae, 0x17, 0xa6,
+    0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a, 0xbf, 0x91, 0xea,
+    0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76, 0x48, 0xc2, 0x1c,
+    0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57, 0xc3, 0xce, 0xcc,
+    0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3, 0x14, 0x9e, 0xe3,
+    0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5, 0x37, 0x8b, 0xae,
+    0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e, 0x37, 0xb7, 0x92,
+    0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66, 0x4d, 0x6a, 0x56,
+    0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71, 0x83, 0x47, 0x2b,
+    0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x01, 0x61, 0xa5,
+    0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9, 0x29, 0xcd, 0xd2,
+    0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b, 0x6d, 0x42,
+    0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5, 0xb9, 0x69,
+    0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc, 0x90, 0x8e,
+    0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55, 0x08, 0x6a,
+    0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a, 0xe1, 0x7a,
+    0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab, 0xf9, 0x1e,
+    0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64, 0x8c, 0x21,
+    0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c, 0x3c, 0xec,
+    0xc9, 0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31, 0x49, 0xee,
+    0x30, 0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53, 0x78, 0xba,
+    0xe0, 0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3, 0x7b, 0x79,
+    0x25, 0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64, 0xd6, 0xa5,
+    0x69, 0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18, 0x34, 0x72,
+    0xbc, 0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70, 0x16, 0x1a,
+    0x59, 0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92, 0x9c, 0xdd,
+    0x2a, 0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4, 0xb6, 0xd4,
+    0x21, 0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e, 0x5b, 0x96,
+    0x95, 0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c, 0xc9, 0x08,
+    0xec, 0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95, 0x50, 0x86,
+    0xaf, 0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10, 0xae, 0x17,
+    0xa6, 0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a, 0xbf, 0x91,
+    0xea, 0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76, 0x48, 0xc2,
+    0x1c, 0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57, 0xc3, 0xce,
+    0xcc, 0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3, 0x14, 0x9e,
+    0xe3, 0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5, 0x37, 0x8b,
+    0xae, 0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e, 0x37, 0xb7,
+    0x92, 0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66, 0x4d, 0x6a,
+    0x56, 0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71, 0x83, 0x47,
+    0x2b, 0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x01, 0x61,
+    0xa5, 0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9, 0x29, 0xcd,
+    0xd2, 0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b, 0x6d,
+    0x42, 0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5, 0xb9,
+    0x69, 0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc, 0x90,
+    0x8e, 0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55, 0x08,
+    0x6a, 0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a, 0xe1,
+    0x7a, 0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab, 0xf9,
+    0x1e, 0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64, 0x8c,
+    0x21, 0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c, 0x3c,
+    0xec, 0xc9, 0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31, 0x49,
+    0xee, 0x30, 0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53, 0x78,
+    0xba, 0xe0, 0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3, 0x7b,
+    0x79, 0x25, 0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64, 0xd6,
+    0xa5, 0x69, 0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18, 0x34,
+    0x72, 0xbc, 0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70, 0x16,
+    0x1a, 0x59, 0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92, 0x9c,
+    0xdd, 0x2a, 0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4, 0xb6,
+    0xd4, 0x21, 0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e, 0x5b,
+    0x96, 0x95, 0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c, 0xc9,
+    0x08, 0xec, 0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95, 0x50,
+    0x86, 0xaf, 0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10, 0xae,
+    0x17, 0xa6, 0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a, 0xbf,
+    0x91, 0xea, 0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76, 0x48,
+    0xc2, 0x1c, 0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57, 0xc3,
+    0xce, 0xcc, 0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3, 0x14,
+    0x9e, 0xe3, 0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5, 0x37,
+    0x8b, 0xae, 0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e, 0x37,
+    0xb7, 0x92, 0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66, 0x4d,
+    0x6a, 0x56, 0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71, 0x83,
+    0x47, 0x2b, 0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7, 0x01,
+    0x61, 0xa5, 0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9, 0x29,
+    0xcd, 0xd2, 0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b, 0x4b,
+    0x6d, 0x42, 0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95, 0xe5,
+    0xb9, 0x69, 0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2, 0xcc,
+    0x90, 0x8e, 0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9, 0x55,
+    0x08, 0x6a, 0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1, 0x0a,
+    0xe1, 0x7a, 0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4, 0xab,
+    0xf9, 0x1e, 0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47, 0x64,
+    0x8c, 0x21, 0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35, 0x7c,
+    0x3c, 0xec, 0xc9, 0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd, 0x31,
+    0x49, 0xee, 0x30, 0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f, 0x53,
+    0x78, 0xba, 0xe0, 0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10, 0xe3,
+    0x7b, 0x79, 0x25, 0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76, 0x64,
+    0xd6, 0xa5, 0x69, 0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7, 0x18,
+    0x34, 0x72, 0xbc, 0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d, 0x70,
+    0x16, 0x1a, 0x59, 0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc, 0x92,
+    0x9c, 0xdd, 0x2a, 0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52, 0xb4,
+    0xb6, 0xd4, 0x21, 0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39, 0x5e,
+    0x5b, 0x96, 0x95, 0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d, 0x2c,
+    0xc9, 0x08, 0xec, 0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e, 0x95,
+    0x50, 0x86, 0xaf, 0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a, 0x10,
+    0xae, 0x17, 0xa6, 0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb, 0x4a,
+    0xbf, 0x91, 0xea, 0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84, 0x76,
+    0x48, 0xc2, 0x1c, 0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43, 0x57,
+    0xc3, 0xce, 0xcc, 0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b, 0xd3,
+    0x14, 0x9e, 0xe3, 0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8, 0xf5,
+    0x37, 0x8b, 0xae, 0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61, 0x0e,
+    0x37, 0xb7, 0x92, 0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7, 0x66,
+    0x4d, 0x6a, 0x56, 0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f, 0x71,
+    0x83, 0x47, 0x2b, 0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5, 0xd7,
+    0x01, 0x61, 0xa5, 0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb, 0xc9,
+    0x29, 0xcd, 0xd2, 0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5, 0x2b,
+    0x4b, 0x6d, 0x42, 0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3, 0x95,
+    0xe5, 0xb9, 0x69, 0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0, 0xd2,
+    0xcc, 0x90, 0x8e, 0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6, 0xe9,
+    0x55, 0x08, 0x6a, 0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6, 0xa1,
+    0x0a, 0xe1, 0x7a, 0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc, 0xb4,
+    0xab, 0xf9, 0x1e, 0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48, 0x47,
+    0x64, 0x8c, 0x21, 0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84, 0x35,
+    0x7c, 0x3c, 0xec, 0xc9, 0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70, 0xbd,
+    0x31, 0x49, 0xee, 0x30, 0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc, 0x8f,
+    0x53, 0x78, 0xba, 0xe0, 0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46, 0x10,
+    0xe3, 0x7b, 0x79, 0x25, 0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e, 0x76,
+    0x64, 0xd6, 0xa5, 0x69, 0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4, 0xf7,
+    0x18, 0x34, 0x72, 0xbc, 0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc, 0x5d,
+    0x70, 0x16, 0x1a, 0x59, 0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd, 0xbc,
+    0x92, 0x9c, 0xdd, 0x2a, 0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b, 0x52,
+    0xb4, 0xb6, 0xd4, 0x21, 0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a, 0x39,
+    0x5e, 0x5b, 0x96, 0x95, 0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b, 0x0d,
+    0x2c, 0xc9, 0x08, 0xec, 0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e, 0x6e,
+    0x95, 0x50, 0x86, 0xaf, 0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b, 0x6a,
+    0x10, 0xae, 0x17, 0xa6, 0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d, 0xcb,
+    0x4a, 0xbf, 0x91, 0xea, 0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64, 0x84,
+    0x76, 0x48, 0xc2, 0x1c, 0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8, 0x43,
+    0x57, 0xc3, 0xce, 0xcc, 0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57, 0x0b,
+    0xd3, 0x14, 0x9e, 0xe3, 0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f, 0xc8,
+    0xf5, 0x37, 0x8b, 0xae, 0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24, 0x61,
+    0x0e, 0x37, 0xb7, 0x92, 0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1, 0xe7,
+    0x66, 0x4d, 0x6a, 0x56, 0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a, 0x4f,
+    0x71, 0x83, 0x47, 0x2b, 0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b, 0xc5,
+    0xd7, 0x01, 0x61, 0xa5, 0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b, 0xdb,
+    0xc9, 0x29, 0xcd, 0xd2, 0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26, 0xb5,
+    0x2b, 0x4b, 0x6d, 0x42, 0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1, 0xa3,
+    0x95, 0xe5, 0xb9, 0x69, 0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80, 0xb0,
+    0xd2, 0xcc, 0x90, 0x8e, 0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94, 0xe6,
+    0xe9, 0x55, 0x08, 0x6a, 0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5, 0xb6,
+    0xa1, 0x0a, 0xe1, 0x7a, 0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2, 0xdc,
+    0xb4, 0xab, 0xf9, 0x1e, 0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66, 0x48,
+    0x47, 0x64, 0x8c, 0x21, 0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x74, 0xaa, 0x84,
+    0x35, 0x7c, 0x3c, 0xec, 0xc9, 0xad, 0x4a, 0xd2, 0xdb, 0x50, 0x85, 0x70,
+    0xbd, 0x31, 0x49, 0xee, 0x30, 0x68, 0xe5, 0x79, 0x6e, 0x5a, 0x55, 0xfc,
+    0x8f, 0x53, 0x78, 0xba, 0xe0, 0x2c, 0x34, 0xb3, 0x24, 0x23, 0xb2, 0x46,
+    0x10, 0xe3, 0x7b, 0x79, 0x25, 0x39, 0xba, 0x55, 0x42, 0x1a, 0xbe, 0x1e,
+    0x76, 0x64, 0xd6, 0xa5, 0x69, 0x6d, 0xa8, 0x42, 0xb8, 0x5e, 0x98, 0xa4,
+    0xf7, 0x18, 0x34, 0x72, 0xbc, 0xb7, 0x2d, 0x2a, 0xfe, 0x47, 0xa9, 0xbc,
+    0x5d, 0x70, 0x16, 0x1a, 0x59, 0x92, 0x11, 0xd9, 0x23, 0x08, 0x71, 0xbd,
+    0xbc, 0x92, 0x9c, 0xdd, 0x2a, 0xa1, 0x0d, 0x5f, 0x0f, 0x3b, 0x32, 0x6b,
+    0x52, 0xb4, 0xb6, 0xd4, 0x21, 0x5c, 0x2f, 0x4c, 0x52, 0x7b, 0x8c, 0x1a,
+    0x39, 0x5e, 0x5b, 0x96, 0x95, 0x7f, 0x23, 0xd4, 0xde, 0x2e, 0xb8, 0x0b,
+    0x0d, 0x2c, 0xc9, 0x08, 0xec, 0x91, 0x84, 0x38, 0xde, 0xde, 0x49, 0x4e,
+    0x6e, 0x95, 0x50, 0x86, 0xaf, 0x87, 0x9d, 0x99, 0x35, 0xa9, 0x5a, 0x5b,
+    0x6a, 0x10, 0xae, 0x17, 0xa6, 0x29, 0x3d, 0xc6, 0x0d, 0x1c, 0xaf, 0x2d,
+    0xcb, 0x4a, 0xbf, 0x91, 0xea, 0x6f, 0x17, 0x5c, 0x05, 0x86, 0x96, 0x64,
+    0x84, 0x76, 0x48, 0xc2, 0x1c, 0x6f, 0x6f, 0x24, 0xa7, 0x37, 0x4a, 0xa8,
+    0x43, 0x57, 0xc3, 0xce, 0xcc, 0x9a, 0xd4, 0xad, 0x2d, 0xb5, 0x08, 0x57,
+    0x0b, 0xd3, 0x14, 0x9e, 0xe3, 0x06, 0x8e, 0x57, 0x96, 0xe5, 0xa5, 0x5f,
+    0xc8, 0xf5, 0x37, 0x8b, 0xae, 0x02, 0xc3, 0x4b, 0x32, 0x42, 0x3b, 0x24,
+    0x61, 0x0e, 0x37, 0xb7, 0x92, 0x53, 0x9b, 0xa5, 0x54, 0x21, 0xab, 0xe1,
+    0xe7, 0x66, 0x4d, 0x6a, 0x56, 0x96, 0xda, 0x84, 0x2b, 0x85, 0xe9, 0x8a,
+    0x4f, 0x71, 0x83, 0x47, 0x2b, 0xcb, 0x72, 0xd2, 0xaf, 0xe4, 0x7a, 0x9b,
+    0xc5, 0xd7, 0x01, 0x61, 0xa5, 0x99, 0x21, 0x1d, 0x92, 0x30, 0x87, 0x1b,
+    0xdb, 0xc9, 0x29, 0xcd, 0xd2, 0xaa, 0x10, 0xd5, 0xf0, 0xf3, 0xb3, 0x26,
+    0xb5, 0x2b, 0x4b, 0x6d, 0x42, 0x15, 0xc2, 0xf4, 0xc5, 0x27, 0xb8, 0xc1,
+    0xa3, 0x95, 0xe5, 0xb9, 0x69, 0x57, 0xf2, 0x3d, 0x4d, 0xe2, 0xeb, 0x80,
+    0xb0, 0xd2, 0xcc, 0x90, 0x8e, 0xc9, 0x18, 0x43, 0x8d, 0xed, 0xe4, 0x94,
+    0xe6, 0xe9, 0x55, 0x08, 0x6a, 0xf8, 0x79, 0xd9, 0x93, 0x5a, 0x95, 0xa5,
+    0xb6, 0xa1, 0x0a, 0xe1, 0x7a, 0x62, 0x93, 0xdc, 0x60, 0xd1, 0xca, 0xf2,
+    0xdc, 0xb4, 0xab, 0xf9, 0x1e, 0xa6, 0xf1, 0x75, 0xc0, 0x58, 0x69, 0x66,
+    0x48, 0x47, 0x64, 0x8c, 0x21, 0xc6, 0xf6, 0xf2, 0x4a, 0x73, 0x75, 0x80,
+};
+static_assert(sizeof(kBytesTestReadSymbol5) == kNumBytesTestReadSymbol5, "");
+
+// The kBytesTestReadSymbol6[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][7] = {
+//   // pmf: 1/6, 1/6, 1/6, 1/6, 1/6, 1/6
+//   { 32768 - 5461, 32768 - 10923, 32768 - 16384, 32768 - 21845, 32768 - 27307,
+//     0, 0 },
+//   // pmf: 3/12, 2/12, 2/12, 2/12, 2/12, 1/12
+//   { 32768 - 8192, 32768 - 13653, 32768 - 19115, 32768 - 24576, 32768 - 30037,
+//     0, 0 },
+//   // pmf: 1/12, 2/12, 2/12, 2/12, 2/12, 3/12
+//   { 32768 - 2731, 32768 - 8192, 32768 - 13653, 32768 - 19115, 32768 - 24576,
+//     0, 0 },
+//   // pmf: 1/12, 2/12, 3/12, 3/12, 2/12, 1/12
+//   { 32768 - 2731, 32768 - 8192, 32768 - 16384, 32768 - 24576, 32768 - 30037,
+//     0, 0 },
+// };
+// constexpr int kSymbols[12][4] = { { 0, 0, 5, 5 },  //
+//                                   { 0, 1, 4, 4 },  //
+//                                   { 1, 2, 3, 3 },  //
+//                                   { 1, 3, 2, 2 },  //
+//                                   { 2, 4, 1, 1 },  //
+//                                   { 2, 5, 0, 0 },  //
+//                                   { 3, 0, 5, 4 },  //
+//                                   { 3, 1, 4, 3 },  //
+//                                   { 4, 2, 3, 2 },  //
+//                                   { 4, 3, 2, 1 },  //
+//                                   { 5, 4, 1, 3 },  //
+//                                   { 5, 0, 5, 2 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 256; ++i) {
+//   for (int j = 0; j < 12; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 6);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol6 = 3917;
+constexpr uint8_t kBytesTestReadSymbol6[] = {
+    0x0a, 0x8e, 0xb8, 0x15, 0xd5, 0x69, 0x63, 0x06, 0x48, 0x75, 0xf4, 0x4c,
+    0xfa, 0x13, 0xba, 0x68, 0x61, 0xa6, 0x9f, 0x39, 0x63, 0xba, 0x63, 0x26,
+    0xa8, 0xaa, 0xd0, 0x10, 0x4a, 0x05, 0xaf, 0x5f, 0x65, 0x57, 0x2f, 0x68,
+    0x48, 0x2c, 0x64, 0xdf, 0x0a, 0x93, 0xcc, 0x84, 0x43, 0x97, 0x34, 0x79,
+    0x10, 0x05, 0x4d, 0x58, 0xe9, 0xc3, 0xb4, 0x4a, 0x70, 0xd4, 0x81, 0x71,
+    0x9f, 0x6b, 0x18, 0xb3, 0x72, 0xdf, 0x37, 0x87, 0x3e, 0x40, 0xd0, 0xff,
+    0x10, 0x32, 0x22, 0xe4, 0x36, 0xef, 0xa2, 0x5e, 0x39, 0x5d, 0x42, 0x59,
+    0x8c, 0x3f, 0x1b, 0x41, 0xdb, 0xc2, 0x8c, 0x64, 0xaf, 0xd2, 0x49, 0x45,
+    0xd8, 0xad, 0x85, 0x3b, 0x70, 0x13, 0x83, 0x63, 0x49, 0x86, 0x35, 0xfe,
+    0x93, 0x6b, 0x51, 0x0e, 0x32, 0x3d, 0xf0, 0x30, 0xe0, 0xf5, 0x42, 0x59,
+    0x33, 0x8e, 0x63, 0x62, 0x46, 0x00, 0x69, 0x06, 0x52, 0x83, 0x37, 0x0b,
+    0x37, 0x12, 0x38, 0x3b, 0x9c, 0xc3, 0x00, 0xed, 0x0a, 0xd4, 0xed, 0x69,
+    0x01, 0xc5, 0x3a, 0x14, 0x29, 0xaf, 0x3e, 0x9c, 0x0a, 0xaf, 0x56, 0x50,
+    0x56, 0xcd, 0xa1, 0xb0, 0x88, 0xef, 0xa7, 0x57, 0xe6, 0xe8, 0x2c, 0x42,
+    0x60, 0x55, 0x22, 0x1f, 0xcc, 0x50, 0xa9, 0xda, 0xc2, 0x73, 0x19, 0x2e,
+    0xfb, 0x74, 0x88, 0x42, 0x0d, 0x49, 0x12, 0x5e, 0x36, 0x43, 0xe7, 0x33,
+    0x00, 0x7d, 0xd5, 0x35, 0xa3, 0xaf, 0x1e, 0x93, 0x5e, 0xe6, 0xae, 0x23,
+    0x41, 0x55, 0x05, 0x19, 0xde, 0xa7, 0xf1, 0x07, 0xbd, 0x58, 0xc1, 0x10,
+    0x0a, 0x4b, 0x5c, 0xee, 0xe3, 0xfb, 0xe5, 0xf5, 0xfc, 0x1a, 0x4e, 0x51,
+    0xda, 0x3e, 0xc5, 0x36, 0xda, 0x3e, 0x83, 0xfd, 0x6b, 0x6f, 0x54, 0xdb,
+    0x68, 0x5a, 0x9c, 0x46, 0xbf, 0x86, 0x23, 0xf1, 0xbd, 0xe1, 0x79, 0x5e,
+    0xf7, 0x1c, 0xe0, 0xf7, 0xa6, 0xd5, 0x9f, 0x0b, 0x74, 0xd8, 0xf2, 0x0a,
+    0x97, 0x71, 0xa2, 0xd2, 0x37, 0x05, 0x7e, 0x3e, 0xa4, 0xec, 0x16, 0x92,
+    0x37, 0xdd, 0x45, 0x0c, 0x17, 0x42, 0xf0, 0x34, 0xf7, 0x38, 0x04, 0xdf,
+    0xb8, 0xb4, 0xd6, 0xa0, 0x2c, 0x56, 0x96, 0x10, 0x30, 0x34, 0x10, 0x39,
+    0x9e, 0x95, 0x3b, 0x13, 0xf3, 0x60, 0xa1, 0x48, 0xca, 0x9f, 0x91, 0xfe,
+    0x42, 0xfb, 0xdf, 0x37, 0xf8, 0x5d, 0x49, 0x82, 0x42, 0x4f, 0x90, 0xdf,
+    0xae, 0x32, 0x20, 0x9e, 0xb6, 0xcc, 0xa0, 0x30, 0x07, 0x15, 0x64, 0xb8,
+    0x56, 0x84, 0x1e, 0x16, 0xa3, 0x35, 0xad, 0x14, 0x9d, 0x62, 0x65, 0x0c,
+    0x77, 0x82, 0x74, 0x41, 0x9c, 0x68, 0x95, 0x03, 0x4f, 0xfc, 0x1c, 0xc7,
+    0xd6, 0xe6, 0xe7, 0xb3, 0x54, 0x66, 0x87, 0xb6, 0x41, 0x03, 0xe2, 0x20,
+    0xf7, 0xdb, 0x2a, 0x0a, 0x25, 0x20, 0x60, 0xdf, 0xfd, 0x9f, 0x5f, 0x2c,
+    0x72, 0x5f, 0x2b, 0xf4, 0x07, 0x9f, 0xf3, 0x8a, 0xde, 0xf0, 0x4f, 0x8a,
+    0xa7, 0x75, 0xe3, 0xe8, 0xc9, 0xa1, 0xa0, 0x01, 0xa1, 0x20, 0xc8, 0xfb,
+    0xf9, 0x91, 0xd2, 0x23, 0x4f, 0x6c, 0x53, 0x3b, 0x12, 0x01, 0xac, 0x1f,
+    0x89, 0x84, 0x98, 0xcd, 0x3c, 0x74, 0x51, 0x92, 0xbe, 0x87, 0x06, 0x62,
+    0x49, 0xd2, 0x1b, 0x27, 0xfa, 0x28, 0xf8, 0xbd, 0xbb, 0x7a, 0x7d, 0xde,
+    0xa2, 0x9c, 0x1b, 0x7c, 0x80, 0xe8, 0xe0, 0x43, 0x64, 0xdd, 0x22, 0x7e,
+    0x2c, 0xe4, 0x79, 0x2e, 0xbd, 0x98, 0x1a, 0x59, 0x7e, 0xbe, 0xfd, 0x9e,
+    0x0c, 0x31, 0x50, 0x10, 0xdd, 0x62, 0x3c, 0x47, 0x9a, 0x11, 0x1b, 0x48,
+    0xf3, 0xd1, 0x2c, 0x1b, 0xc2, 0xb5, 0x57, 0x7c, 0xe5, 0x97, 0x6d, 0x78,
+    0xe7, 0xa2, 0xd6, 0x57, 0x61, 0x95, 0xed, 0x8d, 0xda, 0xc6, 0xdf, 0x2c,
+    0x1d, 0x48, 0xee, 0x53, 0xd8, 0x1e, 0x80, 0x41, 0xce, 0x58, 0x08, 0x96,
+    0x6f, 0x82, 0x6e, 0x28, 0x6a, 0x5a, 0x2b, 0x4f, 0x02, 0x4d, 0x99, 0x32,
+    0xea, 0x60, 0xce, 0x75, 0x57, 0x0c, 0x63, 0xf0, 0xda, 0x51, 0x1d, 0xcc,
+    0xb8, 0x21, 0x35, 0x10, 0x56, 0xaf, 0x80, 0xb3, 0x0f, 0x17, 0x29, 0x0c,
+    0x16, 0x07, 0x66, 0xe9, 0xcb, 0x52, 0xcd, 0xec, 0xb1, 0x79, 0xf8, 0xb9,
+    0x05, 0x08, 0xa1, 0xd7, 0x03, 0x6f, 0x8e, 0x9a, 0x6e, 0xfb, 0x38, 0x3a,
+    0xff, 0xa7, 0xa1, 0xd8, 0xb1, 0x56, 0x06, 0xde, 0xb1, 0xe7, 0x47, 0xc2,
+    0xc2, 0xab, 0xa9, 0x5f, 0x01, 0x65, 0x5d, 0x4c, 0xac, 0xd8, 0x1c, 0xfd,
+    0x2d, 0x55, 0x74, 0x8a, 0x2b, 0x41, 0x2d, 0x50, 0x0c, 0x9c, 0x64, 0xb2,
+    0xed, 0xaf, 0x2a, 0xb4, 0x58, 0x93, 0xd8, 0xc2, 0xab, 0x04, 0x45, 0xfc,
+    0xd7, 0x02, 0x1e, 0x14, 0xd4, 0x38, 0xba, 0x24, 0x07, 0x9a, 0x25, 0x52,
+    0x13, 0xe1, 0xe4, 0x26, 0x66, 0x12, 0xba, 0x13, 0x11, 0x25, 0xea, 0x29,
+    0xc5, 0xff, 0x34, 0xca, 0x18, 0x34, 0x97, 0x4a, 0x92, 0x00, 0xe8, 0x61,
+    0x18, 0x85, 0x0b, 0x56, 0x83, 0x48, 0xf9, 0xdb, 0x26, 0x7b, 0x54, 0xc8,
+    0xd2, 0x63, 0x1e, 0x7b, 0x25, 0x3c, 0x4a, 0xa6, 0xda, 0x10, 0x92, 0xca,
+    0x8a, 0x2c, 0x89, 0x60, 0x8e, 0xda, 0xf2, 0xab, 0x45, 0x89, 0x3d, 0x8c,
+    0x2d, 0x35, 0xda, 0xc1, 0x7c, 0x3d, 0x05, 0x8e, 0xad, 0x5b, 0xff, 0x7d,
+    0x46, 0x7b, 0x74, 0x71, 0xec, 0x05, 0x9a, 0x85, 0xa4, 0x4f, 0xc3, 0x54,
+    0x64, 0x90, 0xe5, 0x97, 0x89, 0x1a, 0xb0, 0x56, 0x30, 0x13, 0xda, 0x44,
+    0x2c, 0xb0, 0x50, 0x0c, 0x64, 0x43, 0x4a, 0xd2, 0x2a, 0xb4, 0x8f, 0x9d,
+    0xa6, 0xe5, 0x3c, 0x0c, 0x7a, 0x44, 0xb3, 0xeb, 0xa7, 0x92, 0xe5, 0x59,
+    0xa6, 0x43, 0xe9, 0x2b, 0x1f, 0x69, 0x4a, 0xc4, 0x89, 0xe7, 0xe0, 0x04,
+    0x9f, 0x1d, 0x33, 0x61, 0xe8, 0xab, 0x75, 0x8d, 0x30, 0xd6, 0x7c, 0xca,
+    0x02, 0xbe, 0xf9, 0x1d, 0x02, 0x4e, 0x0f, 0x88, 0xc9, 0x3f, 0x54, 0x9d,
+    0x93, 0x0d, 0x44, 0xf8, 0xf6, 0xa7, 0x1a, 0xb6, 0x8b, 0xf5, 0x14, 0xca,
+    0xbd, 0x6c, 0x2d, 0x9e, 0xfa, 0x80, 0x36, 0x53, 0x06, 0xac, 0x39, 0x0f,
+    0x6b, 0xdb, 0x2e, 0xe0, 0x4f, 0xf0, 0xa4, 0x44, 0x5a, 0xbb, 0xaa, 0x72,
+    0x59, 0x3f, 0x58, 0x38, 0xe5, 0x5c, 0x76, 0x31, 0xe6, 0xfe, 0x08, 0x20,
+    0xbe, 0x3f, 0xea, 0x00, 0x0d, 0x34, 0xd9, 0x4d, 0x06, 0x0a, 0xb5, 0x04,
+    0x7b, 0x48, 0x22, 0xa9, 0x94, 0x47, 0x44, 0xfd, 0x65, 0x81, 0x45, 0x56,
+    0x91, 0xf3, 0xb4, 0xdc, 0xa7, 0x6e, 0xb1, 0xa4, 0xc5, 0xd6, 0x81, 0x6a,
+    0x78, 0x94, 0x8a, 0xa4, 0x21, 0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d,
+    0xa7, 0xa7, 0xf2, 0x17, 0x92, 0x06, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12,
+    0x7f, 0x99, 0x40, 0x57, 0xdf, 0x23, 0xa0, 0x49, 0xc1, 0xf1, 0x19, 0x27,
+    0xea, 0x93, 0xb2, 0x61, 0xa8, 0x9f, 0x1e, 0xd4, 0xe3, 0x56, 0xd1, 0x7e,
+    0xa2, 0x99, 0x57, 0xad, 0x85, 0xb3, 0xdf, 0x50, 0x06, 0xca, 0x60, 0xd5,
+    0x87, 0x21, 0xed, 0x7b, 0x65, 0xdc, 0x09, 0xfe, 0x14, 0x88, 0x8b, 0x57,
+    0x75, 0x4e, 0x4b, 0x27, 0xeb, 0x07, 0x1c, 0xab, 0x8e, 0xc6, 0x3c, 0xdf,
+    0xc1, 0x04, 0x17, 0xc7, 0xfd, 0x40, 0x01, 0xa6, 0x9b, 0x29, 0xa0, 0xc1,
+    0x56, 0xa0, 0x8f, 0x69, 0x04, 0x55, 0x32, 0x88, 0xe8, 0x9f, 0x8d, 0x2b,
+    0x48, 0xaa, 0xd2, 0x3e, 0x76, 0x9b, 0x94, 0xed, 0xd6, 0x34, 0x98, 0xba,
+    0x16, 0x3c, 0x29, 0xce, 0x3d, 0x14, 0x84, 0x24, 0xac, 0x7d, 0xa4, 0xaa,
+    0x30, 0xcb, 0xb4, 0xdd, 0xe3, 0x7a, 0x0e, 0x78, 0xc8, 0xcb, 0x75, 0x59,
+    0x0e, 0x82, 0x4f, 0xf3, 0x28, 0x0a, 0xf6, 0x18, 0x41, 0xa0, 0x7c, 0xe5,
+    0xff, 0xf2, 0xf9, 0x07, 0xe7, 0x99, 0x4c, 0xa6, 0x10, 0xa7, 0x08, 0x46,
+    0x84, 0xa5, 0x22, 0xa9, 0x08, 0x49, 0x58, 0xfb, 0x49, 0x54, 0x61, 0x97,
+    0x69, 0xbb, 0xc6, 0xf4, 0x1c, 0xf1, 0x91, 0x96, 0xea, 0xb2, 0x1d, 0x04,
+    0x9f, 0xe6, 0x50, 0x15, 0xec, 0x30, 0x83, 0x40, 0xf9, 0xcb, 0xff, 0xe5,
+    0xf2, 0x0f, 0xcf, 0x32, 0x99, 0x4c, 0x21, 0x4e, 0x10, 0x8d, 0x09, 0x4a,
+    0x45, 0x52, 0x10, 0x92, 0xb1, 0xf6, 0x92, 0xa8, 0xc3, 0x2e, 0xd3, 0x77,
+    0x8d, 0xe8, 0x39, 0xe3, 0x23, 0x2d, 0xd5, 0x64, 0x3a, 0x09, 0x3f, 0xcc,
+    0xa0, 0x2b, 0xd8, 0x61, 0x06, 0x81, 0xf3, 0x97, 0xff, 0xcb, 0xe4, 0x1f,
+    0x9e, 0x65, 0x32, 0x98, 0x42, 0x9c, 0x21, 0x1a, 0x12, 0x94, 0x8a, 0xa4,
+    0x21, 0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d, 0xa6, 0xef, 0x1b, 0xd0,
+    0x73, 0xc6, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12, 0x7f, 0x99, 0x40, 0x57,
+    0xb0, 0xc2, 0x0d, 0x03, 0xe7, 0x2f, 0xff, 0x97, 0xc8, 0x3f, 0x3c, 0xca,
+    0x65, 0x30, 0x85, 0x38, 0x42, 0x34, 0x25, 0x29, 0x15, 0x48, 0x42, 0x4a,
+    0xc7, 0xda, 0x4a, 0xa3, 0x0c, 0xbb, 0x4d, 0xde, 0x37, 0xa0, 0xe7, 0x8c,
+    0x8c, 0xb7, 0x55, 0x90, 0xe8, 0x24, 0xff, 0x32, 0x80, 0xaf, 0x61, 0x84,
+    0x1a, 0x07, 0xce, 0x5f, 0xff, 0x2f, 0x90, 0x7e, 0x79, 0x94, 0xca, 0x61,
+    0x0a, 0x70, 0x84, 0x68, 0x4a, 0x52, 0x2a, 0x90, 0x84, 0x95, 0x8f, 0xb4,
+    0x95, 0x46, 0x19, 0x76, 0x9b, 0xbc, 0x6f, 0x41, 0xcf, 0x19, 0x19, 0x6e,
+    0xab, 0x21, 0xd0, 0x49, 0xfe, 0x65, 0x01, 0x5e, 0xc3, 0x08, 0x34, 0x0f,
+    0x9c, 0xbf, 0xfe, 0x5f, 0x20, 0xfc, 0xf3, 0x29, 0x94, 0xc2, 0x14, 0xe1,
+    0x08, 0xd0, 0x94, 0xa4, 0x55, 0x21, 0x09, 0x2b, 0x1f, 0x69, 0x2a, 0x8c,
+    0x32, 0xed, 0x37, 0x78, 0xde, 0x83, 0x9e, 0x32, 0x32, 0xdd, 0x56, 0x43,
+    0xa0, 0x93, 0xfc, 0xca, 0x02, 0xbd, 0x86, 0x10, 0x68, 0x1f, 0x39, 0x7f,
+    0xfc, 0xbe, 0x41, 0xf9, 0xe6, 0x53, 0x29, 0x84, 0x29, 0xc2, 0x11, 0xa1,
+    0x29, 0x48, 0xaa, 0x42, 0x12, 0x56, 0x3e, 0xd2, 0x55, 0x18, 0x65, 0xda,
+    0x6e, 0xf1, 0xbd, 0x07, 0x3c, 0x64, 0x65, 0xba, 0xac, 0x87, 0x41, 0x27,
+    0xf9, 0x94, 0x05, 0x7b, 0x0c, 0x20, 0xd0, 0x3e, 0x72, 0xff, 0xf9, 0x7c,
+    0x83, 0xf3, 0xcc, 0xa6, 0x53, 0x08, 0x53, 0x84, 0x23, 0x42, 0x52, 0x91,
+    0x54, 0x84, 0x24, 0xac, 0x7d, 0xa4, 0xaa, 0x30, 0xcb, 0xb4, 0xdd, 0xe3,
+    0x7a, 0x0e, 0x78, 0xc8, 0xcb, 0x75, 0x59, 0x0e, 0x82, 0x4f, 0xf3, 0x28,
+    0x0a, 0xf6, 0x18, 0x41, 0xa0, 0x7c, 0xe5, 0xff, 0xf2, 0xf9, 0x07, 0xe7,
+    0x99, 0x4c, 0xa6, 0x10, 0xa7, 0x08, 0x46, 0x84, 0xa5, 0x22, 0xa9, 0x08,
+    0x49, 0x58, 0xfb, 0x49, 0x54, 0x61, 0x97, 0x69, 0xbb, 0xc6, 0xf4, 0x1c,
+    0xf1, 0x91, 0x96, 0xea, 0xb2, 0x1d, 0x04, 0x9f, 0xe6, 0x50, 0x15, 0xec,
+    0x30, 0x83, 0x40, 0xf9, 0xcb, 0xff, 0xe5, 0xf2, 0x0f, 0xcf, 0x32, 0x99,
+    0x4c, 0x21, 0x4e, 0x10, 0x8d, 0x09, 0x4a, 0x45, 0x52, 0x10, 0x92, 0xb1,
+    0xf6, 0x92, 0xa8, 0xc3, 0x2e, 0xd3, 0x77, 0x8d, 0xe8, 0x39, 0xe3, 0x23,
+    0x2d, 0xd5, 0x64, 0x3a, 0x09, 0x3f, 0xcc, 0xa0, 0x2b, 0xd8, 0x61, 0x06,
+    0x81, 0xf3, 0x97, 0xff, 0xcb, 0xe4, 0x1f, 0x9e, 0x65, 0x32, 0x98, 0x42,
+    0x9c, 0x21, 0x1a, 0x12, 0x94, 0x8a, 0xa4, 0x21, 0x25, 0x63, 0xed, 0x25,
+    0x51, 0x86, 0x5d, 0xa6, 0xef, 0x1b, 0xd0, 0x73, 0xc6, 0x46, 0x5b, 0xaa,
+    0xc8, 0x74, 0x12, 0x7f, 0x99, 0x40, 0x57, 0xb0, 0xc2, 0x0d, 0x03, 0xe7,
+    0x2f, 0xff, 0x97, 0xc8, 0x3f, 0x3c, 0xca, 0x65, 0x30, 0x85, 0x38, 0x42,
+    0x34, 0x25, 0x29, 0x15, 0x48, 0x42, 0x4a, 0xc7, 0xda, 0x4a, 0xa3, 0x0c,
+    0xbb, 0x4d, 0xde, 0x37, 0xa0, 0xe7, 0x8c, 0x8c, 0xb7, 0x55, 0x90, 0xe8,
+    0x24, 0xff, 0x32, 0x80, 0xaf, 0x61, 0x84, 0x1a, 0x07, 0xce, 0x5f, 0xff,
+    0x2f, 0x90, 0x7e, 0x79, 0x94, 0xca, 0x61, 0x0a, 0x70, 0x84, 0x68, 0x4a,
+    0x52, 0x2a, 0x90, 0x84, 0x95, 0x8f, 0xb4, 0x95, 0x46, 0x19, 0x76, 0x9b,
+    0xbc, 0x6f, 0x41, 0xcf, 0x19, 0x19, 0x6e, 0xab, 0x21, 0xd0, 0x49, 0xfe,
+    0x65, 0x01, 0x5e, 0xc3, 0x08, 0x34, 0x0f, 0x9c, 0xbf, 0xfe, 0x5f, 0x20,
+    0xfc, 0xf3, 0x29, 0x94, 0xc2, 0x14, 0xe1, 0x08, 0xd0, 0x94, 0xa4, 0x55,
+    0x21, 0x09, 0x2b, 0x1f, 0x69, 0x2a, 0x8c, 0x32, 0xed, 0x37, 0x78, 0xde,
+    0x83, 0x9e, 0x32, 0x32, 0xdd, 0x56, 0x43, 0xa0, 0x93, 0xfc, 0xca, 0x02,
+    0xbd, 0x86, 0x10, 0x68, 0x1f, 0x39, 0x7f, 0xfc, 0xbe, 0x41, 0xf9, 0xe6,
+    0x53, 0x29, 0x84, 0x29, 0xc2, 0x11, 0xa1, 0x29, 0x48, 0xaa, 0x42, 0x12,
+    0x56, 0x3e, 0xd2, 0x55, 0x18, 0x65, 0xda, 0x6e, 0xf1, 0xbd, 0x07, 0x3c,
+    0x64, 0x65, 0xba, 0xac, 0x87, 0x41, 0x27, 0xf9, 0x94, 0x05, 0x7b, 0x0c,
+    0x20, 0xd0, 0x3e, 0x72, 0xff, 0xf9, 0x7c, 0x83, 0xf3, 0xcc, 0xa6, 0x53,
+    0x08, 0x53, 0x84, 0x23, 0x42, 0x52, 0x91, 0x54, 0x84, 0x24, 0xac, 0x7d,
+    0xa4, 0xaa, 0x30, 0xcb, 0xb4, 0xdd, 0xe3, 0x7a, 0x0e, 0x78, 0xc8, 0xcb,
+    0x75, 0x59, 0x0e, 0x82, 0x4f, 0xf3, 0x28, 0x0a, 0xf6, 0x18, 0x41, 0xa0,
+    0x7c, 0xe5, 0xff, 0xf2, 0xf9, 0x07, 0xe7, 0x99, 0x4c, 0xa6, 0x10, 0xa7,
+    0x08, 0x46, 0x84, 0xa5, 0x22, 0xa9, 0x08, 0x49, 0x58, 0xfb, 0x49, 0x54,
+    0x61, 0x97, 0x69, 0xbb, 0xc6, 0xf4, 0x1c, 0xf1, 0x91, 0x96, 0xea, 0xb2,
+    0x1d, 0x04, 0x9f, 0xe6, 0x50, 0x15, 0xec, 0x30, 0x83, 0x40, 0xf9, 0xcb,
+    0xff, 0xe5, 0xf2, 0x0f, 0xcf, 0x32, 0x99, 0x4c, 0x21, 0x4e, 0x10, 0x8d,
+    0x09, 0x4a, 0x45, 0x52, 0x10, 0x92, 0xb1, 0xf6, 0x92, 0xa8, 0xc3, 0x2e,
+    0xd3, 0x77, 0x8d, 0xe8, 0x39, 0xe3, 0x23, 0x2d, 0xd5, 0x64, 0x3a, 0x09,
+    0x3f, 0xcc, 0xa0, 0x2b, 0xd8, 0x61, 0x06, 0x81, 0xf3, 0x97, 0xff, 0xcb,
+    0xe4, 0x1f, 0x9e, 0x65, 0x32, 0x98, 0x42, 0x9c, 0x21, 0x1a, 0x12, 0x94,
+    0x8a, 0xa4, 0x21, 0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d, 0xa6, 0xef,
+    0x1b, 0xd0, 0x73, 0xc6, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12, 0x7f, 0x99,
+    0x40, 0x57, 0xb0, 0xc2, 0x0d, 0x03, 0xe7, 0x2f, 0xff, 0x97, 0xc8, 0x3f,
+    0x3c, 0xca, 0x65, 0x30, 0x85, 0x38, 0x42, 0x34, 0x25, 0x29, 0x15, 0x48,
+    0x42, 0x4a, 0xc7, 0xda, 0x4a, 0xa3, 0x0c, 0xbb, 0x4d, 0xde, 0x37, 0xa0,
+    0xe7, 0x8c, 0x8c, 0xb7, 0x55, 0x90, 0xe8, 0x24, 0xff, 0x32, 0x80, 0xaf,
+    0x61, 0x84, 0x1a, 0x07, 0xce, 0x5f, 0xff, 0x2f, 0x90, 0x7e, 0x79, 0x94,
+    0xca, 0x61, 0x0a, 0x70, 0x84, 0x68, 0x4a, 0x52, 0x2a, 0x90, 0x84, 0x95,
+    0x8f, 0xb4, 0x95, 0x46, 0x19, 0x76, 0x9b, 0xbc, 0x6f, 0x41, 0xcf, 0x19,
+    0x19, 0x6e, 0xab, 0x21, 0xd0, 0x49, 0xfe, 0x65, 0x01, 0x5e, 0xc3, 0x08,
+    0x34, 0x0f, 0x9c, 0xbf, 0xfe, 0x5f, 0x20, 0xfc, 0xf3, 0x29, 0x94, 0xc2,
+    0x14, 0xe1, 0x08, 0xd0, 0x94, 0xa4, 0x55, 0x21, 0x09, 0x2b, 0x1f, 0x69,
+    0x2a, 0x8c, 0x32, 0xed, 0x37, 0x78, 0xde, 0x83, 0x9e, 0x32, 0x32, 0xdd,
+    0x56, 0x43, 0xa0, 0x93, 0xfc, 0xca, 0x02, 0xbd, 0x86, 0x10, 0x68, 0x1f,
+    0x39, 0x7f, 0xfc, 0xbe, 0x41, 0xf9, 0xe6, 0x53, 0x29, 0x84, 0x29, 0xc2,
+    0x11, 0xa1, 0x29, 0x48, 0xaa, 0x42, 0x12, 0x56, 0x3e, 0xd2, 0x55, 0x18,
+    0x65, 0xda, 0x6e, 0xf1, 0xbd, 0x07, 0x3c, 0x64, 0x65, 0xba, 0xac, 0x87,
+    0x41, 0x27, 0xf9, 0x94, 0x05, 0x7b, 0x0c, 0x20, 0xd0, 0x3e, 0x72, 0xff,
+    0xf9, 0x7c, 0x83, 0xf3, 0xcc, 0xa6, 0x53, 0x08, 0x53, 0x84, 0x23, 0x42,
+    0x52, 0x91, 0x54, 0x84, 0x24, 0xac, 0x7d, 0xa4, 0xaa, 0x30, 0xcb, 0xb4,
+    0xdd, 0xe3, 0x7a, 0x0e, 0x78, 0xc8, 0xcb, 0x75, 0x59, 0x0e, 0x82, 0x4f,
+    0xf3, 0x28, 0x0a, 0xf6, 0x18, 0x41, 0xa0, 0x7c, 0xe5, 0xff, 0xf2, 0xf9,
+    0x07, 0xe7, 0x99, 0x4c, 0xa6, 0x10, 0xa7, 0x08, 0x46, 0x84, 0xa5, 0x22,
+    0xa9, 0x08, 0x49, 0x58, 0xfb, 0x49, 0x54, 0x61, 0x97, 0x69, 0xbb, 0xc6,
+    0xf4, 0x1c, 0xf1, 0x91, 0x96, 0xea, 0xb2, 0x1d, 0x04, 0x9f, 0xe6, 0x50,
+    0x15, 0xec, 0x30, 0x83, 0x40, 0xf9, 0xcb, 0xff, 0xe5, 0xf2, 0x0f, 0xcf,
+    0x32, 0x99, 0x4c, 0x21, 0x4e, 0x10, 0x8d, 0x09, 0x4a, 0x45, 0x52, 0x10,
+    0x92, 0xb1, 0xf6, 0x92, 0xa8, 0xc3, 0x2e, 0xd3, 0x77, 0x8d, 0xe8, 0x39,
+    0xe3, 0x23, 0x2d, 0xd5, 0x64, 0x3a, 0x09, 0x3f, 0xcc, 0xa0, 0x2b, 0xd8,
+    0x61, 0x06, 0x81, 0xf3, 0x97, 0xff, 0xcb, 0xe4, 0x1f, 0x9e, 0x65, 0x32,
+    0x98, 0x42, 0x9c, 0x21, 0x1a, 0x12, 0x94, 0x8a, 0xa4, 0x21, 0x25, 0x63,
+    0xed, 0x25, 0x51, 0x86, 0x5d, 0xa6, 0xef, 0x1b, 0xd0, 0x73, 0xc6, 0x46,
+    0x5b, 0xaa, 0xc8, 0x74, 0x12, 0x7f, 0x99, 0x40, 0x57, 0xb0, 0xc2, 0x0d,
+    0x03, 0xe7, 0x2f, 0xff, 0x97, 0xc8, 0x3f, 0x3c, 0xca, 0x65, 0x30, 0x85,
+    0x38, 0x42, 0x34, 0x25, 0x29, 0x15, 0x48, 0x42, 0x4a, 0xc7, 0xda, 0x4a,
+    0xa3, 0x0c, 0xbb, 0x4d, 0xde, 0x37, 0xa0, 0xe7, 0x8c, 0x8c, 0xb7, 0x55,
+    0x90, 0xe8, 0x24, 0xff, 0x32, 0x80, 0xaf, 0x61, 0x84, 0x1a, 0x07, 0xce,
+    0x5f, 0xff, 0x2f, 0x90, 0x7e, 0x79, 0x94, 0xca, 0x61, 0x0a, 0x70, 0x84,
+    0x68, 0x4a, 0x52, 0x2a, 0x90, 0x84, 0x95, 0x8f, 0xb4, 0x95, 0x46, 0x19,
+    0x76, 0x9b, 0xbc, 0x6f, 0x41, 0xcf, 0x19, 0x19, 0x6e, 0xab, 0x21, 0xd0,
+    0x49, 0xfe, 0x65, 0x01, 0x5e, 0xc3, 0x08, 0x34, 0x0f, 0x9c, 0xbf, 0xfe,
+    0x5f, 0x20, 0xfc, 0xf3, 0x29, 0x94, 0xc2, 0x14, 0xe1, 0x08, 0xd0, 0x94,
+    0xa4, 0x55, 0x21, 0x09, 0x2b, 0x1f, 0x69, 0x2a, 0x8c, 0x32, 0xed, 0x37,
+    0x78, 0xde, 0x83, 0x9e, 0x32, 0x32, 0xdd, 0x56, 0x43, 0xa0, 0x93, 0xfc,
+    0xca, 0x02, 0xbd, 0x86, 0x10, 0x68, 0x1f, 0x39, 0x7f, 0xfc, 0xbe, 0x41,
+    0xf9, 0xe6, 0x53, 0x29, 0x84, 0x29, 0xc2, 0x11, 0xa1, 0x29, 0x48, 0xaa,
+    0x42, 0x12, 0x56, 0x3e, 0xd2, 0x55, 0x18, 0x65, 0xda, 0x6e, 0xf1, 0xbd,
+    0x07, 0x3c, 0x64, 0x65, 0xba, 0xac, 0x87, 0x41, 0x27, 0xf9, 0x94, 0x05,
+    0x7b, 0x0c, 0x20, 0xd0, 0x3e, 0x72, 0xff, 0xf9, 0x7c, 0x83, 0xf3, 0xcc,
+    0xa6, 0x53, 0x08, 0x53, 0x84, 0x23, 0x42, 0x52, 0x91, 0x54, 0x84, 0x24,
+    0xac, 0x7d, 0xa4, 0xaa, 0x30, 0xcb, 0xb4, 0xdd, 0xe3, 0x7a, 0x0e, 0x78,
+    0xc8, 0xcb, 0x75, 0x59, 0x0e, 0x82, 0x4f, 0xf3, 0x28, 0x0a, 0xf6, 0x18,
+    0x41, 0xa0, 0x7c, 0xe5, 0xff, 0xf2, 0xf9, 0x07, 0xe7, 0x99, 0x4c, 0xa6,
+    0x10, 0xa7, 0x08, 0x46, 0x84, 0xa5, 0x22, 0xa9, 0x08, 0x49, 0x58, 0xfb,
+    0x49, 0x54, 0x61, 0x97, 0x69, 0xbb, 0xc6, 0xf4, 0x1c, 0xf1, 0x91, 0x96,
+    0xea, 0xb2, 0x1d, 0x04, 0x9f, 0xe6, 0x50, 0x15, 0xec, 0x30, 0x83, 0x40,
+    0xf9, 0xcb, 0xff, 0xe5, 0xf2, 0x0f, 0xcf, 0x32, 0x99, 0x4c, 0x21, 0x4e,
+    0x10, 0x8d, 0x09, 0x4a, 0x45, 0x52, 0x10, 0x92, 0xb1, 0xf6, 0x92, 0xa8,
+    0xc3, 0x2e, 0xd3, 0x77, 0x8d, 0xe8, 0x39, 0xe3, 0x23, 0x2d, 0xd5, 0x64,
+    0x3a, 0x09, 0x3f, 0xcc, 0xa0, 0x2b, 0xd8, 0x61, 0x06, 0x81, 0xf3, 0x97,
+    0xff, 0xcb, 0xe4, 0x1f, 0x9e, 0x65, 0x32, 0x98, 0x42, 0x9c, 0x21, 0x1a,
+    0x12, 0x94, 0x8a, 0xa4, 0x21, 0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d,
+    0xa6, 0xef, 0x1b, 0xd0, 0x73, 0xc6, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12,
+    0x7f, 0x99, 0x40, 0x57, 0xb0, 0xc2, 0x0d, 0x03, 0xe7, 0x2f, 0xff, 0x97,
+    0xc8, 0x3f, 0x3c, 0xca, 0x65, 0x30, 0x85, 0x38, 0x42, 0x34, 0x25, 0x29,
+    0x15, 0x48, 0x42, 0x4a, 0xc7, 0xda, 0x4a, 0xa3, 0x0c, 0xbb, 0x4d, 0xde,
+    0x37, 0xa0, 0xe7, 0x8c, 0x8c, 0xb7, 0x55, 0x90, 0xe8, 0x24, 0xff, 0x32,
+    0x80, 0xaf, 0x61, 0x84, 0x1a, 0x07, 0xce, 0x5f, 0xff, 0x2f, 0x90, 0x7e,
+    0x79, 0x94, 0xca, 0x61, 0x0a, 0x70, 0x84, 0x68, 0x4a, 0x52, 0x2a, 0x90,
+    0x84, 0x95, 0x8f, 0xb4, 0x95, 0x46, 0x19, 0x76, 0x9b, 0xbc, 0x6f, 0x41,
+    0xcf, 0x19, 0x19, 0x6e, 0xab, 0x21, 0xd0, 0x49, 0xfe, 0x65, 0x01, 0x5e,
+    0xc3, 0x08, 0x34, 0x0f, 0x9c, 0xbf, 0xfe, 0x5f, 0x20, 0xfc, 0xf3, 0x29,
+    0x94, 0xc2, 0x14, 0xe1, 0x08, 0xd0, 0x94, 0xa4, 0x55, 0x21, 0x09, 0x2b,
+    0x1f, 0x69, 0x2a, 0x8c, 0x32, 0xed, 0x37, 0x78, 0xde, 0x83, 0x9e, 0x32,
+    0x32, 0xdd, 0x56, 0x43, 0xa0, 0x93, 0xfc, 0xca, 0x02, 0xbd, 0x86, 0x10,
+    0x68, 0x1f, 0x39, 0x7f, 0xfc, 0xbe, 0x41, 0xf9, 0xe6, 0x53, 0x29, 0x84,
+    0x29, 0xc2, 0x11, 0xa1, 0x29, 0x48, 0xaa, 0x42, 0x12, 0x56, 0x3e, 0xd2,
+    0x55, 0x18, 0x65, 0xda, 0x6e, 0xf1, 0xbd, 0x07, 0x3c, 0x64, 0x65, 0xba,
+    0xac, 0x87, 0x41, 0x27, 0xf9, 0x94, 0x05, 0x7b, 0x0c, 0x20, 0xd0, 0x3e,
+    0x72, 0xff, 0xf9, 0x7c, 0x83, 0xf3, 0xcc, 0xa6, 0x53, 0x08, 0x53, 0x84,
+    0x23, 0x42, 0x52, 0x91, 0x54, 0x84, 0x24, 0xac, 0x7d, 0xa4, 0xaa, 0x30,
+    0xcb, 0xb4, 0xdd, 0xe3, 0x7a, 0x0e, 0x78, 0xc8, 0xcb, 0x75, 0x59, 0x0e,
+    0x82, 0x4f, 0xf3, 0x28, 0x0a, 0xf6, 0x18, 0x41, 0xa0, 0x7c, 0xe5, 0xff,
+    0xf2, 0xf9, 0x07, 0xe7, 0x99, 0x4c, 0xa6, 0x10, 0xa7, 0x08, 0x46, 0x84,
+    0xa5, 0x22, 0xa9, 0x08, 0x49, 0x58, 0xfb, 0x49, 0x54, 0x61, 0x97, 0x69,
+    0xbb, 0xc6, 0xf4, 0x1c, 0xf1, 0x91, 0x96, 0xea, 0xb2, 0x1d, 0x04, 0x9f,
+    0xe6, 0x50, 0x15, 0xec, 0x30, 0x83, 0x40, 0xf9, 0xcb, 0xff, 0xe5, 0xf2,
+    0x0f, 0xcf, 0x32, 0x99, 0x4c, 0x21, 0x4e, 0x10, 0x8d, 0x09, 0x4a, 0x45,
+    0x52, 0x10, 0x92, 0xb1, 0xf6, 0x92, 0xa8, 0xc3, 0x2e, 0xd3, 0x77, 0x8d,
+    0xe8, 0x39, 0xe3, 0x23, 0x2d, 0xd5, 0x64, 0x3a, 0x09, 0x3f, 0xcc, 0xa0,
+    0x2b, 0xd8, 0x61, 0x06, 0x81, 0xf3, 0x97, 0xff, 0xcb, 0xe4, 0x1f, 0x9e,
+    0x65, 0x32, 0x98, 0x42, 0x9c, 0x21, 0x1a, 0x12, 0x94, 0x8a, 0xa4, 0x21,
+    0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d, 0xa6, 0xef, 0x1b, 0xd0, 0x73,
+    0xc6, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12, 0x7f, 0x99, 0x40, 0x57, 0xb0,
+    0xc2, 0x0d, 0x03, 0xe7, 0x2f, 0xff, 0x97, 0xc8, 0x3f, 0x3c, 0xca, 0x65,
+    0x30, 0x85, 0x38, 0x42, 0x34, 0x25, 0x29, 0x15, 0x48, 0x42, 0x4a, 0xc7,
+    0xda, 0x4a, 0xa3, 0x0c, 0xbb, 0x4d, 0xde, 0x37, 0xa0, 0xe7, 0x8c, 0x8c,
+    0xb7, 0x55, 0x90, 0xe8, 0x24, 0xff, 0x32, 0x80, 0xaf, 0x61, 0x84, 0x1a,
+    0x07, 0xce, 0x5f, 0xff, 0x2f, 0x90, 0x7e, 0x79, 0x94, 0xca, 0x61, 0x0a,
+    0x70, 0x84, 0x68, 0x4a, 0x52, 0x2a, 0x90, 0x84, 0x95, 0x8f, 0xb4, 0x95,
+    0x46, 0x19, 0x76, 0x9b, 0xbc, 0x6f, 0x41, 0xcf, 0x19, 0x19, 0x6e, 0xab,
+    0x21, 0xd0, 0x49, 0xfe, 0x65, 0x01, 0x5e, 0xc3, 0x08, 0x34, 0x0f, 0x9c,
+    0xbf, 0xfe, 0x5f, 0x20, 0xfc, 0xf3, 0x29, 0x94, 0xc2, 0x14, 0xe1, 0x08,
+    0xd0, 0x94, 0xa4, 0x55, 0x21, 0x09, 0x2b, 0x1f, 0x69, 0x2a, 0x8c, 0x32,
+    0xed, 0x37, 0x78, 0xde, 0x83, 0x9e, 0x32, 0x32, 0xdd, 0x56, 0x43, 0xa0,
+    0x93, 0xfc, 0xca, 0x02, 0xbd, 0x86, 0x10, 0x68, 0x1f, 0x39, 0x7f, 0xfc,
+    0xbe, 0x41, 0xf9, 0xe6, 0x53, 0x29, 0x84, 0x29, 0xc2, 0x11, 0xa1, 0x29,
+    0x48, 0xaa, 0x42, 0x12, 0x56, 0x3e, 0xd2, 0x55, 0x18, 0x65, 0xda, 0x6e,
+    0xf1, 0xbd, 0x07, 0x3c, 0x64, 0x65, 0xba, 0xac, 0x87, 0x41, 0x27, 0xf9,
+    0x94, 0x05, 0x7b, 0x0c, 0x20, 0xd0, 0x3e, 0x72, 0xff, 0xf9, 0x7c, 0x83,
+    0xf3, 0xcc, 0xa6, 0x53, 0x08, 0x53, 0x84, 0x23, 0x42, 0x52, 0x91, 0x54,
+    0x84, 0x24, 0xac, 0x7d, 0xa4, 0xaa, 0x30, 0xcb, 0xb4, 0xdd, 0xe3, 0x7a,
+    0x0e, 0x78, 0xc8, 0xcb, 0x75, 0x59, 0x0e, 0x82, 0x4f, 0xf3, 0x28, 0x0a,
+    0xf6, 0x18, 0x41, 0xa0, 0x7c, 0xe5, 0xff, 0xf2, 0xf9, 0x07, 0xe7, 0x99,
+    0x4c, 0xa6, 0x10, 0xa7, 0x08, 0x46, 0x84, 0xa5, 0x22, 0xa9, 0x08, 0x49,
+    0x58, 0xfb, 0x49, 0x54, 0x61, 0x97, 0x69, 0xbb, 0xc6, 0xf4, 0x1c, 0xf1,
+    0x91, 0x96, 0xea, 0xb2, 0x1d, 0x04, 0x9f, 0xe6, 0x50, 0x15, 0xec, 0x30,
+    0x83, 0x40, 0xf9, 0xcb, 0xff, 0xe5, 0xf2, 0x0f, 0xcf, 0x32, 0x99, 0x4c,
+    0x21, 0x4e, 0x10, 0x8d, 0x09, 0x4a, 0x45, 0x52, 0x10, 0x92, 0xb1, 0xf6,
+    0x92, 0xa8, 0xc3, 0x2e, 0xd3, 0x77, 0x8d, 0xe8, 0x39, 0xe3, 0x23, 0x2d,
+    0xd5, 0x64, 0x3a, 0x09, 0x3f, 0xcc, 0xa0, 0x2b, 0xd8, 0x61, 0x06, 0x81,
+    0xf3, 0x97, 0xff, 0xcb, 0xe4, 0x1f, 0x9e, 0x65, 0x32, 0x98, 0x42, 0x9c,
+    0x21, 0x1a, 0x12, 0x94, 0x8a, 0xa4, 0x21, 0x25, 0x63, 0xed, 0x25, 0x51,
+    0x86, 0x5d, 0xa6, 0xef, 0x1b, 0xd0, 0x73, 0xc6, 0x46, 0x5b, 0xaa, 0xc8,
+    0x74, 0x12, 0x7f, 0x99, 0x40, 0x57, 0xb0, 0xc2, 0x0d, 0x03, 0xe7, 0x2f,
+    0xff, 0x97, 0xc8, 0x3f, 0x3c, 0xca, 0x65, 0x30, 0x85, 0x38, 0x42, 0x34,
+    0x25, 0x29, 0x15, 0x48, 0x42, 0x4a, 0xc7, 0xda, 0x4a, 0xa3, 0x0c, 0xbb,
+    0x4d, 0xde, 0x37, 0xa0, 0xe7, 0x8c, 0x8c, 0xb7, 0x55, 0x90, 0xe8, 0x24,
+    0xff, 0x32, 0x80, 0xaf, 0x61, 0x84, 0x1a, 0x07, 0xce, 0x5f, 0xff, 0x2f,
+    0x90, 0x7e, 0x79, 0x94, 0xca, 0x61, 0x0a, 0x70, 0x84, 0x68, 0x4a, 0x52,
+    0x2a, 0x90, 0x84, 0x95, 0x8f, 0xb4, 0x95, 0x46, 0x19, 0x76, 0x9b, 0xbc,
+    0x6f, 0x41, 0xcf, 0x19, 0x19, 0x6e, 0xab, 0x21, 0xd0, 0x49, 0xfe, 0x65,
+    0x01, 0x5e, 0xc3, 0x08, 0x34, 0x0f, 0x9c, 0xbf, 0xfe, 0x5f, 0x20, 0xfc,
+    0xf3, 0x29, 0x94, 0xc2, 0x14, 0xe1, 0x08, 0xd0, 0x94, 0xa4, 0x55, 0x21,
+    0x09, 0x2b, 0x1f, 0x69, 0x2a, 0x8c, 0x32, 0xed, 0x37, 0x78, 0xde, 0x83,
+    0x9e, 0x32, 0x32, 0xdd, 0x56, 0x43, 0xa0, 0x93, 0xfc, 0xca, 0x02, 0xbd,
+    0x86, 0x10, 0x68, 0x1f, 0x39, 0x7f, 0xfc, 0xbe, 0x41, 0xf9, 0xe6, 0x53,
+    0x29, 0x84, 0x29, 0xc2, 0x11, 0xa1, 0x29, 0x48, 0xaa, 0x42, 0x12, 0x56,
+    0x3e, 0xd2, 0x55, 0x18, 0x65, 0xda, 0x6e, 0xf1, 0xbd, 0x07, 0x3c, 0x64,
+    0x65, 0xba, 0xac, 0x87, 0x41, 0x27, 0xf9, 0x94, 0x05, 0x7b, 0x0c, 0x20,
+    0xd0, 0x3e, 0x72, 0xff, 0xf9, 0x7c, 0x83, 0xf3, 0xcc, 0xa6, 0x53, 0x08,
+    0x53, 0x84, 0x23, 0x42, 0x52, 0x91, 0x54, 0x84, 0x24, 0xac, 0x7d, 0xa4,
+    0xaa, 0x30, 0xcb, 0xb4, 0xdd, 0xe3, 0x7a, 0x0e, 0x78, 0xc8, 0xcb, 0x75,
+    0x59, 0x0e, 0x82, 0x4f, 0xf3, 0x28, 0x0a, 0xf6, 0x18, 0x41, 0xa0, 0x7c,
+    0xe5, 0xff, 0xf2, 0xf9, 0x07, 0xe7, 0x99, 0x4c, 0xa6, 0x10, 0xa7, 0x08,
+    0x46, 0x84, 0xa5, 0x22, 0xa9, 0x08, 0x49, 0x58, 0xfb, 0x49, 0x54, 0x61,
+    0x97, 0x69, 0xbb, 0xc6, 0xf4, 0x1c, 0xf1, 0x91, 0x96, 0xea, 0xb2, 0x1d,
+    0x04, 0x9f, 0xe6, 0x50, 0x15, 0xec, 0x30, 0x83, 0x40, 0xf9, 0xcb, 0xff,
+    0xe5, 0xf2, 0x0f, 0xcf, 0x32, 0x99, 0x4c, 0x21, 0x4e, 0x10, 0x8d, 0x09,
+    0x4a, 0x45, 0x52, 0x10, 0x92, 0xb1, 0xf6, 0x92, 0xa8, 0xc3, 0x2e, 0xd3,
+    0x77, 0x8d, 0xe8, 0x39, 0xe3, 0x23, 0x2d, 0xd5, 0x64, 0x3a, 0x09, 0x3f,
+    0xcc, 0xa0, 0x2b, 0xd8, 0x61, 0x06, 0x81, 0xf3, 0x97, 0xff, 0xcb, 0xe4,
+    0x1f, 0x9e, 0x65, 0x32, 0x98, 0x42, 0x9c, 0x21, 0x1a, 0x12, 0x94, 0x8a,
+    0xa4, 0x21, 0x25, 0x63, 0xed, 0x25, 0x51, 0x86, 0x5d, 0xa6, 0xef, 0x1b,
+    0xd0, 0x73, 0xc6, 0x46, 0x5b, 0xaa, 0xc8, 0x74, 0x12, 0x7f, 0x99, 0x40,
+    0x57, 0xb0, 0xc2, 0x0d, 0x03, 0xe7, 0x2f, 0xff, 0x97, 0xc8, 0x3f, 0x3c,
+    0xca, 0x65, 0x30, 0x85, 0x38, 0x42, 0x34, 0x25, 0x29, 0x15, 0x48, 0x42,
+    0x4a, 0xc7, 0xda, 0x4a, 0xa3, 0x0c, 0xbb, 0x4d, 0xde, 0x37, 0xa0, 0xe7,
+    0x8c, 0x8c, 0xb7, 0x55, 0x90, 0xe8, 0x24, 0xff, 0x32, 0x80, 0xaf, 0x61,
+    0x84, 0x1a, 0x07, 0xce, 0x5f, 0xff, 0x2f, 0x90, 0x7e, 0x79, 0x94, 0xca,
+    0x61, 0x0a, 0x70, 0x84, 0x68, 0x4a, 0x52, 0x2a, 0x90, 0x84, 0x95, 0x8f,
+    0xb4, 0x95, 0x46, 0x19, 0x76, 0x9b, 0xbc, 0x6f, 0x41, 0xcf, 0x19, 0x19,
+    0x6e, 0xab, 0x21, 0xd0, 0x49, 0xfe, 0x65, 0x01, 0x5e, 0xc3, 0x08, 0x34,
+    0x0f, 0x9c, 0xbf, 0xfe, 0x5f, 0x20, 0xfc, 0xf3, 0x29, 0x94, 0xc2, 0x14,
+    0xe1, 0x08, 0xd0, 0x94, 0xa4, 0x55, 0x21, 0x09, 0x2b, 0x1f, 0x69, 0x2a,
+    0x8c, 0x32, 0xed, 0x37, 0x78, 0xde, 0x83, 0x9e, 0x32, 0x32, 0xdd, 0x56,
+    0x43, 0xa0, 0x93, 0xfc, 0xca, 0x02, 0xbd, 0x86, 0x10, 0x68, 0x1f, 0x39,
+    0x7f, 0xfc, 0xbe, 0x41, 0xf9, 0xe6, 0x53, 0x29, 0x84, 0x29, 0xc2, 0x11,
+    0xa1, 0x29, 0x48, 0xaa, 0x42, 0x12, 0x56, 0x3e, 0xd2, 0x55, 0x18, 0x65,
+    0xda, 0x6e, 0xf1, 0xbd, 0x07, 0x3c, 0x64, 0x65, 0xba, 0xac, 0x87, 0x41,
+    0x27, 0xf9, 0x94, 0x05, 0xa0,
+};
+static_assert(sizeof(kBytesTestReadSymbol6) == kNumBytesTestReadSymbol6, "");
+
+// The kBytesTestReadSymbol7[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][8] = {
+//   // pdf: 1/7, 1/7, 1/7, 1/7, 1/7, 1/7, 1/7
+//   { 32768 - 4681, 32768 - 9362, 32768 - 14043, 32768 - 18725,
+//     32768 - 23406, 32768 - 28087, 0, 0 },
+//   // pdf: 3/14, 2/14, 2/14, 2/14, 2/14, 2/14, 1/14
+//   { 32768 - 7022, 32768 - 11703, 32768 - 16384, 32768 - 21065,
+//     32768 - 25746, 32768 - 30427, 0, 0 },
+//   // pdf: 1/14, 1/14, 2/14, 2/14, 2/14, 3/14, 3/14
+//   { 32768 - 2341, 32768 - 4681, 32768 - 9362, 32768 - 14043,
+//     32768 - 18725, 32768 - 25746, 0, 0 },
+//   // pdf: 1/14, 2/14, 3/14, 3/14, 2/14, 2/14, 1/14
+//   { 32768 - 2341, 32768 - 7022, 32768 - 14043, 32768 - 21065,
+//     32768 - 25746, 32768 - 30427, 0, 0 },
+// };
+// constexpr int kSymbols[14][4] = { { 0, 4, 6, 3 },  //
+//                                   { 1, 5, 5, 2 },  //
+//                                   { 2, 6, 4, 1 },  //
+//                                   { 3, 0, 3, 0 },  //
+//                                   { 4, 1, 2, 6 },  //
+//                                   { 5, 2, 1, 5 },  //
+//                                   { 6, 3, 0, 4 },  //
+//                                   { 0, 0, 6, 5 },  //
+//                                   { 2, 1, 4, 3 },  //
+//                                   { 4, 3, 6, 1 },  //
+//                                   { 6, 5, 2, 4 },  //
+//                                   { 1, 0, 5, 2 },  //
+//                                   { 3, 2, 3, 2 },  //
+//                                   { 5, 4, 5, 3 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 1024; ++i) {
+//   for (int j = 0; j < 14; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 7);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("  constexpr size_t kNumBytesTestReadSymbol7 = %u;\n", bw.pos);
+// printf("  constexpr uint8_t kBytesTestReadSymbol7[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n      ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n  };\n");
+
+constexpr size_t kNumBytesTestReadSymbol7 = 19874;
+constexpr uint8_t kBytesTestReadSymbol7[] = {
+    0x1c, 0x6a, 0xfc, 0x4b, 0xd1, 0xb5, 0x8c, 0x20, 0x72, 0x45, 0x48, 0x21,
+    0x9e, 0x71, 0xe8, 0xc4, 0x91, 0x51, 0xab, 0xfd, 0x9c, 0x61, 0xf7, 0x98,
+    0xd4, 0x87, 0x71, 0xe6, 0x23, 0x37, 0x7e, 0xa3, 0xe0, 0x83, 0x48, 0x2e,
+    0xfe, 0xc3, 0xcb, 0x4f, 0x26, 0x9a, 0xd7, 0xe4, 0xca, 0xf4, 0x94, 0xb7,
+    0xbc, 0x03, 0xc9, 0xc3, 0x5e, 0x7f, 0xef, 0x9b, 0x37, 0xff, 0x8f, 0x62,
+    0xec, 0xb6, 0x09, 0x50, 0xa9, 0xc1, 0x4a, 0x97, 0xf4, 0xe7, 0x08, 0x57,
+    0x87, 0x2d, 0x10, 0xca, 0xbc, 0x93, 0x85, 0xfb, 0xc8, 0xc7, 0x8f, 0xc1,
+    0x4e, 0x1f, 0x50, 0xad, 0xba, 0x09, 0x9c, 0xf8, 0x94, 0x75, 0xdd, 0x2c,
+    0x78, 0x5d, 0xa0, 0x4a, 0xf3, 0x7b, 0xc0, 0xa7, 0x71, 0xa5, 0x20, 0xe6,
+    0xb0, 0xca, 0x09, 0xf2, 0x38, 0xfc, 0x61, 0x49, 0xdc, 0x83, 0x35, 0x1e,
+    0xdd, 0x08, 0xd7, 0xaa, 0x50, 0x0e, 0xc5, 0x57, 0x05, 0x44, 0xd7, 0xdb,
+    0x56, 0x2b, 0x1e, 0xe5, 0x33, 0x08, 0x7c, 0x3d, 0x25, 0x29, 0x05, 0x14,
+    0x3a, 0x93, 0xff, 0xe7, 0x40, 0x25, 0x30, 0x17, 0xc3, 0x50, 0xad, 0xec,
+    0xb3, 0x64, 0x87, 0x35, 0xb2, 0x5a, 0x1e, 0xa9, 0x48, 0xc8, 0x53, 0x30,
+    0xf1, 0x43, 0x6f, 0xe1, 0x2a, 0x8b, 0x81, 0x49, 0xbc, 0xa8, 0x8a, 0x8b,
+    0x2d, 0x1a, 0xc5, 0xcb, 0x47, 0xc1, 0xbc, 0xe0, 0x54, 0x98, 0xcc, 0x82,
+    0xe9, 0xa6, 0x3f, 0x70, 0x55, 0xe3, 0xe0, 0x7d, 0x5f, 0xa9, 0xc4, 0xc1,
+    0x62, 0x04, 0x2d, 0x15, 0xce, 0xab, 0x7c, 0xd9, 0x88, 0xc1, 0x67, 0x88,
+    0x3d, 0x6e, 0x96, 0x03, 0x6f, 0xa7, 0x6a, 0xc2, 0x6f, 0x20, 0x8c, 0xf4,
+    0xfb, 0x96, 0x0c, 0xb7, 0x14, 0xef, 0xa6, 0x83, 0xbd, 0x2b, 0x07, 0x8a,
+    0x2a, 0x66, 0xb8, 0x0d, 0xa8, 0x72, 0x2a, 0x78, 0x90, 0x2a, 0xe4, 0x46,
+    0x71, 0x8c, 0xcb, 0xcb, 0xbd, 0xfb, 0xc7, 0xa8, 0x9e, 0x9b, 0x6e, 0x6d,
+    0x2b, 0xc2, 0x1c, 0xea, 0x16, 0x3a, 0x06, 0xc0, 0xbc, 0xd7, 0x30, 0x8d,
+    0x87, 0x03, 0x04, 0x0d, 0x58, 0x58, 0x7b, 0x40, 0xf5, 0xe5, 0x7a, 0x51,
+    0x80, 0x7a, 0x16, 0xc2, 0xaf, 0x83, 0x43, 0x16, 0xb3, 0x3a, 0x1b, 0x24,
+    0x29, 0x80, 0x60, 0xee, 0x00, 0x91, 0x15, 0xdb, 0x28, 0x0d, 0xc2, 0xfb,
+    0x74, 0x48, 0xd9, 0x54, 0x97, 0x66, 0xa4, 0xba, 0xc8, 0x19, 0xff, 0x25,
+    0xca, 0xdf, 0x09, 0x66, 0xe4, 0xfe, 0xbb, 0x2b, 0x3f, 0x4a, 0x81, 0x5a,
+    0xa6, 0x54, 0x5c, 0xf0, 0xe4, 0x49, 0x38, 0x13, 0xfb, 0xa2, 0xee, 0xf9,
+    0x7d, 0x72, 0xa9, 0x37, 0x12, 0xf4, 0x04, 0x4e, 0x50, 0x19, 0x6f, 0x29,
+    0x9d, 0x0d, 0xe7, 0xc3, 0x6d, 0x65, 0x0b, 0x04, 0x53, 0x57, 0x0c, 0xb5,
+    0x71, 0xb4, 0xd6, 0xb0, 0xaa, 0xed, 0x38, 0x9e, 0x58, 0x55, 0x0d, 0xe4,
+    0xe6, 0x43, 0x16, 0x93, 0x46, 0x73, 0x39, 0x87, 0xaa, 0x69, 0x07, 0x9f,
+    0xd7, 0xb6, 0x77, 0x7d, 0xef, 0xc7, 0x19, 0x5d, 0x4f, 0x60, 0x20, 0x7e,
+    0xf0, 0x34, 0xbe, 0xe4, 0x31, 0xf3, 0x72, 0xe0, 0x89, 0xfb, 0xc8, 0x0a,
+    0xa9, 0xe6, 0x2c, 0x6b, 0xa5, 0xaa, 0xd5, 0x42, 0x69, 0xc0, 0x27, 0x3b,
+    0x17, 0x98, 0x73, 0xa3, 0x66, 0x10, 0xd7, 0xac, 0xf9, 0x7f, 0xb2, 0xf3,
+    0x38, 0x45, 0x23, 0xe2, 0xd4, 0xd2, 0x63, 0x1c, 0x84, 0xde, 0x25, 0xd4,
+    0x3c, 0x76, 0x58, 0x1a, 0xb6, 0x07, 0x22, 0x74, 0xc2, 0xf7, 0x2c, 0xe1,
+    0xc0, 0x51, 0x8c, 0xfa, 0xde, 0x6b, 0x35, 0x8c, 0x0f, 0x45, 0xf8, 0x5e,
+    0x61, 0x2d, 0x4e, 0x90, 0x2d, 0xb7, 0x6c, 0xaf, 0x71, 0x72, 0xdf, 0x68,
+    0xa9, 0xa2, 0x36, 0x79, 0xbd, 0xee, 0x88, 0xb0, 0xc8, 0xc9, 0xa6, 0x7e,
+    0x8e, 0xe8, 0x16, 0xbc, 0xd6, 0x82, 0x54, 0xac, 0x81, 0x42, 0x0f, 0xc9,
+    0x38, 0xd2, 0xe1, 0x17, 0x17, 0x4f, 0xc9, 0x0c, 0x39, 0xc0, 0x70, 0xd8,
+    0xd8, 0x17, 0x37, 0x4a, 0x93, 0x40, 0x83, 0xe3, 0x3f, 0x05, 0x25, 0xab,
+    0x6e, 0x58, 0xc1, 0x30, 0x62, 0x4d, 0xad, 0xcd, 0x1b, 0x7a, 0x4b, 0x08,
+    0xf8, 0x69, 0x85, 0xf1, 0x10, 0x84, 0x22, 0x54, 0x3a, 0x0c, 0x2d, 0x1b,
+    0xcd, 0x2d, 0xed, 0x95, 0x63, 0x1a, 0x9e, 0xbc, 0xb8, 0x76, 0x48, 0x65,
+    0xd1, 0xa6, 0x22, 0x98, 0x3e, 0xda, 0x00, 0x56, 0xf4, 0xd3, 0xc5, 0xb0,
+    0xb3, 0xb0, 0xfa, 0x0c, 0x84, 0x43, 0xfb, 0xa1, 0x1a, 0xba, 0x23, 0xc6,
+    0x72, 0xea, 0x83, 0x96, 0xff, 0xfd, 0x0d, 0xba, 0x40, 0x32, 0x3e, 0x1a,
+    0x61, 0x7b, 0xd5, 0x50, 0xfe, 0x41, 0xc8, 0x67, 0x71, 0xb4, 0xff, 0x24,
+    0xf8, 0x7b, 0xa2, 0x6d, 0x97, 0x84, 0x8e, 0x36, 0x30, 0x05, 0xc3, 0x60,
+    0x3b, 0x1c, 0xee, 0x34, 0x57, 0x05, 0x0f, 0x9e, 0xc2, 0xfd, 0xc8, 0x03,
+    0xab, 0x8a, 0x54, 0xde, 0x6a, 0x22, 0xa5, 0xb7, 0x38, 0xf5, 0x91, 0x08,
+    0xd4, 0xce, 0xe3, 0xa7, 0xb4, 0xcb, 0x58, 0x79, 0xe2, 0x34, 0x79, 0xfa,
+    0xc2, 0x85, 0x01, 0xeb, 0x53, 0xf1, 0xca, 0x5c, 0xa1, 0xfc, 0x35, 0xa2,
+    0x7b, 0x8f, 0x29, 0x1c, 0x67, 0xb0, 0x01, 0x1b, 0x5a, 0xa1, 0xc9, 0x3b,
+    0x2c, 0xc6, 0x35, 0xbb, 0x29, 0x46, 0x13, 0xfa, 0xd9, 0x40, 0x63, 0x3e,
+    0x6c, 0xa2, 0x36, 0x70, 0xe7, 0xc8, 0x76, 0x55, 0x70, 0xd2, 0x3f, 0xd1,
+    0xae, 0x83, 0x9d, 0xb9, 0x60, 0x47, 0x3e, 0x38, 0x0d, 0x08, 0x3f, 0xe0,
+    0x6b, 0x16, 0x7f, 0x7d, 0x7d, 0x40, 0x98, 0x99, 0xc1, 0x27, 0xf2, 0xb5,
+    0xfe, 0x33, 0xce, 0x83, 0x8c, 0x7d, 0xa7, 0xe6, 0xeb, 0x06, 0xdb, 0x4f,
+    0xca, 0x10, 0x82, 0x7b, 0x5e, 0xe8, 0xa9, 0x2e, 0xe0, 0x7a, 0xc2, 0x03,
+    0x75, 0x6e, 0x4e, 0x2b, 0xb6, 0xc3, 0x99, 0xf5, 0x41, 0xe9, 0x75, 0xe5,
+    0xc5, 0xae, 0x4f, 0xa8, 0x57, 0xf5, 0xf5, 0x89, 0x60, 0xae, 0x41, 0x13,
+    0x91, 0x77, 0x84, 0xb6, 0x79, 0xea, 0xcb, 0xeb, 0x8d, 0x05, 0xe2, 0x18,
+    0xfd, 0x36, 0x1f, 0x68, 0x34, 0xd1, 0x3c, 0xc3, 0xe1, 0x87, 0xd3, 0x2a,
+    0xb1, 0xc5, 0xac, 0xe2, 0xc3, 0xaf, 0xd1, 0x53, 0x61, 0x5e, 0xba, 0xcb,
+    0x32, 0xde, 0x97, 0xee, 0x4e, 0x58, 0xda, 0xda, 0x9d, 0x12, 0xe2, 0x75,
+    0x20, 0xd5, 0xb4, 0x64, 0x82, 0x75, 0x3e, 0xee, 0xb9, 0x13, 0x54, 0x54,
+    0x95, 0x36, 0x36, 0xa9, 0x85, 0x34, 0xa2, 0x37, 0xa0, 0x55, 0xe7, 0x1e,
+    0x9e, 0xb8, 0xbf, 0x36, 0x96, 0x1b, 0x1c, 0xa9, 0x16, 0xa9, 0x66, 0xb6,
+    0x30, 0x91, 0xc6, 0xfb, 0x51, 0x30, 0xc8, 0x19, 0x91, 0xca, 0x9e, 0x99,
+    0x88, 0x5a, 0x29, 0xbc, 0x10, 0x8e, 0x21, 0x93, 0x4b, 0xd1, 0x10, 0x10,
+    0x10, 0xca, 0x1a, 0x4d, 0x95, 0xd5, 0x0a, 0x08, 0xe4, 0xbc, 0xbc, 0xd4,
+    0xc4, 0x48, 0xaa, 0xb7, 0x55, 0x88, 0x55, 0x59, 0xfa, 0x05, 0x17, 0xae,
+    0x2f, 0xcd, 0xa5, 0x86, 0xc7, 0x2a, 0x45, 0xaa, 0x59, 0xad, 0x8c, 0x24,
+    0x71, 0xbe, 0xd4, 0x4c, 0x32, 0x06, 0x64, 0x72, 0xa7, 0xa6, 0x62, 0x16,
+    0x8a, 0x6f, 0x04, 0x23, 0x88, 0x64, 0xd2, 0xf4, 0x44, 0x04, 0x04, 0x32,
+    0x86, 0x93, 0x65, 0x75, 0x42, 0x82, 0x39, 0x2f, 0x2f, 0x35, 0x31, 0x12,
+    0x2a, 0xad, 0xd5, 0x62, 0x15, 0x56, 0x7e, 0x81, 0x48, 0x8e, 0xd3, 0x5e,
+    0x73, 0x9d, 0xa3, 0xec, 0xca, 0xdd, 0xbe, 0x89, 0xd7, 0xb8, 0xa3, 0x59,
+    0xeb, 0x97, 0xb3, 0xf2, 0xf1, 0xa6, 0x4b, 0x8e, 0x89, 0xe6, 0xe9, 0x0a,
+    0x84, 0x9b, 0xbf, 0xd3, 0x6b, 0xd5, 0xbf, 0x1e, 0x7f, 0x87, 0x55, 0x76,
+    0x5e, 0xa7, 0xe6, 0x3e, 0xcf, 0x6c, 0x16, 0x5f, 0xf1, 0xf6, 0xf0, 0x3e,
+    0xd4, 0x4f, 0x71, 0xe5, 0x23, 0x8c, 0xf6, 0xa6, 0x11, 0xc3, 0xf8, 0x7b,
+    0xc7, 0xea, 0x1a, 0x6a, 0xc7, 0x13, 0x2e, 0x5a, 0xf6, 0x61, 0x9b, 0x71,
+    0x61, 0x3b, 0x66, 0x37, 0xd4, 0x28, 0xa6, 0xbf, 0xd6, 0xc6, 0x2e, 0x29,
+    0xd6, 0x38, 0xb5, 0x9c, 0x58, 0x75, 0xfa, 0x2a, 0x6c, 0x2f, 0xa3, 0x8b,
+    0x02, 0xbe, 0xdd, 0x38, 0xdb, 0x4f, 0xca, 0x25, 0x43, 0x09, 0x44, 0x79,
+    0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x45, 0xaa, 0x53, 0x29, 0x8e, 0xd7, 0x81,
+    0x74, 0xdd, 0xfa, 0x65, 0x18, 0xd5, 0xc5, 0xae, 0x4f, 0xa8, 0x57, 0xf6,
+    0x04, 0xf5, 0xcd, 0xd8, 0xa0, 0x26, 0xb4, 0x41, 0xe3, 0x02, 0xc9, 0x95,
+    0xfe, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0xe6, 0x35, 0xff, 0x03,
+    0x5f, 0x8c, 0xac, 0x56, 0x1e, 0xec, 0x29, 0xfc, 0x45, 0x97, 0x61, 0x74,
+    0xa6, 0xed, 0x7c, 0x67, 0x7a, 0xf5, 0xdd, 0x80, 0xaf, 0x42, 0x04, 0x7f,
+    0x82, 0x46, 0x15, 0x56, 0xea, 0xb1, 0x0a, 0xab, 0x3f, 0x40, 0xa4, 0x47,
+    0x69, 0xaf, 0x39, 0xce, 0xd1, 0xf6, 0x65, 0x6e, 0xf0, 0x45, 0x5e, 0xfc,
+    0x51, 0xac, 0xf5, 0xcb, 0xd9, 0xf9, 0x78, 0xd3, 0x25, 0xc7, 0x44, 0xf3,
+    0x74, 0x85, 0x42, 0x4d, 0xdf, 0xe9, 0xb5, 0xea, 0xdf, 0x8f, 0x3f, 0xc3,
+    0xaa, 0xbb, 0x2f, 0x53, 0xf3, 0x1f, 0x67, 0xb6, 0x0b, 0x2f, 0xf8, 0xfb,
+    0x78, 0x1f, 0x6a, 0x27, 0xb8, 0xf2, 0x91, 0xc6, 0x7b, 0x53, 0x08, 0xe1,
+    0xfc, 0x3d, 0xe3, 0xf5, 0x0d, 0x35, 0x63, 0x89, 0x97, 0x2d, 0x7b, 0x30,
+    0xcd, 0xb8, 0xb0, 0x9d, 0xb3, 0x1b, 0xea, 0x14, 0x53, 0x5f, 0xeb, 0x63,
+    0x17, 0x14, 0xeb, 0x1c, 0x5a, 0xce, 0x2c, 0x3a, 0xfd, 0x15, 0x36, 0x17,
+    0xd1, 0xc5, 0x81, 0x5f, 0x6e, 0x9c, 0x6d, 0xa7, 0xe5, 0x12, 0xa1, 0x84,
+    0xa2, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x22, 0xd5, 0x29, 0x94, 0xc7,
+    0x6b, 0xc0, 0xba, 0x6e, 0xfd, 0x32, 0x8c, 0x6a, 0xe2, 0xd7, 0x27, 0xd4,
+    0x2b, 0xfb, 0x02, 0x7a, 0xe6, 0xec, 0x50, 0x13, 0x5a, 0x20, 0xf1, 0x81,
+    0x64, 0xca, 0xff, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x73, 0x1a,
+    0xff, 0x81, 0xaf, 0xc6, 0x56, 0x2b, 0x0f, 0x76, 0x14, 0xfe, 0x22, 0xcb,
+    0xb0, 0xba, 0x53, 0x76, 0xbe, 0x33, 0xbd, 0x7a, 0xee, 0xc0, 0x57, 0xa1,
+    0x02, 0x3f, 0xc1, 0x23, 0x0a, 0xab, 0x75, 0x58, 0x85, 0x55, 0x9f, 0xa0,
+    0x52, 0x23, 0xb4, 0xd7, 0x9c, 0xe7, 0x68, 0xfb, 0x32, 0xb7, 0x78, 0x22,
+    0xaf, 0x7e, 0x28, 0xd6, 0x7a, 0xe5, 0xec, 0xfc, 0xbc, 0x69, 0x92, 0xe3,
+    0xa2, 0x79, 0xba, 0x42, 0xa1, 0x26, 0xef, 0xf4, 0xda, 0xf5, 0x6f, 0xc7,
+    0x9f, 0xe1, 0xd5, 0x5d, 0x97, 0xa9, 0xf9, 0x8f, 0xb3, 0xdb, 0x05, 0x97,
+    0xfc, 0x7d, 0xbc, 0x0f, 0xb5, 0x13, 0xdc, 0x79, 0x48, 0xe3, 0x3d, 0xa9,
+    0x84, 0x70, 0xfe, 0x1e, 0xf1, 0xfa, 0x86, 0x9a, 0xb1, 0xc4, 0xcb, 0x96,
+    0xbd, 0x98, 0x66, 0xdc, 0x58, 0x4e, 0xd9, 0x8d, 0xf5, 0x0a, 0x29, 0xaf,
+    0xf5, 0xb1, 0x8b, 0x8a, 0x75, 0x8e, 0x2d, 0x67, 0x16, 0x1d, 0x7e, 0x8a,
+    0x9b, 0x0b, 0xe8, 0xe2, 0xc0, 0xaf, 0xb7, 0x4e, 0x36, 0xd3, 0xf2, 0x89,
+    0x50, 0xc2, 0x51, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x91, 0x6a, 0x94,
+    0xca, 0x63, 0xb5, 0xe0, 0x5d, 0x37, 0x7e, 0x99, 0x46, 0x35, 0x71, 0x6b,
+    0x93, 0xea, 0x15, 0xfd, 0x81, 0x3d, 0x73, 0x76, 0x28, 0x09, 0xad, 0x10,
+    0x78, 0xc0, 0xb2, 0x65, 0x7f, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70,
+    0x39, 0x8d, 0x7f, 0xc0, 0xd7, 0xe3, 0x2b, 0x15, 0x87, 0xbb, 0x0a, 0x7f,
+    0x11, 0x65, 0xd8, 0x5d, 0x29, 0xbb, 0x5f, 0x19, 0xde, 0xbd, 0x77, 0x60,
+    0x2b, 0xd0, 0x81, 0x1f, 0xe0, 0x91, 0x85, 0x55, 0xba, 0xac, 0x42, 0xaa,
+    0xcf, 0xd0, 0x29, 0x11, 0xda, 0x6b, 0xce, 0x73, 0xb4, 0x7d, 0x99, 0x5b,
+    0xbc, 0x11, 0x57, 0xbf, 0x14, 0x6b, 0x3d, 0x72, 0xf6, 0x7e, 0x5e, 0x34,
+    0xc9, 0x71, 0xd1, 0x3c, 0xdd, 0x21, 0x50, 0x93, 0x77, 0xfa, 0x6d, 0x7a,
+    0xb7, 0xe3, 0xcf, 0xf0, 0xea, 0xae, 0xe7, 0x1d, 0xfb, 0x2a, 0x2f, 0x0e,
+    0xe3, 0xde, 0xf4, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f,
+    0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90,
+    0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d,
+    0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13,
+    0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49,
+    0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc,
+    0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5,
+    0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a,
+    0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04,
+    0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd,
+    0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba,
+    0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b,
+    0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88,
+    0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7,
+    0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17,
+    0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68,
+    0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf,
+    0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73,
+    0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32,
+    0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61,
+    0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc,
+    0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a,
+    0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a,
+    0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1,
+    0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7,
+    0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b,
+    0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6,
+    0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff,
+    0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18,
+    0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8,
+    0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa,
+    0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa,
+    0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62,
+    0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d,
+    0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6,
+    0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97,
+    0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41,
+    0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb,
+    0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb,
+    0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9,
+    0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda,
+    0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f,
+    0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c,
+    0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84,
+    0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84,
+    0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6,
+    0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74,
+    0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92,
+    0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc,
+    0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51,
+    0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2,
+    0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2,
+    0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a,
+    0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb,
+    0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3,
+    0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c,
+    0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23,
+    0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01,
+    0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe,
+    0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c,
+    0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e,
+    0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c,
+    0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d,
+    0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86,
+    0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c,
+    0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f,
+    0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1,
+    0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc,
+    0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06,
+    0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3,
+    0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d,
+    0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0,
+    0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32,
+    0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6,
+    0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31,
+    0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64,
+    0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a,
+    0xbf, 0x79, 0x95, 0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c,
+    0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea,
+    0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41,
+    0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d,
+    0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5,
+    0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca,
+    0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60,
+    0x87, 0x11, 0xd9, 0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01,
+    0x07, 0xef, 0x37, 0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b,
+    0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98,
+    0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66,
+    0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a,
+    0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf,
+    0xde, 0x65, 0x50, 0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07,
+    0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e,
+    0x9d, 0x79, 0xee, 0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47,
+    0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f,
+    0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42,
+    0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a,
+    0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21,
+    0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41,
+    0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2,
+    0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21,
+    0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2,
+    0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9,
+    0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7,
+    0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4,
+    0xb0, 0xc5, 0x37, 0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7,
+    0x5e, 0x7b, 0xa5, 0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0,
+    0x8d, 0x6c, 0x93, 0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7,
+    0xbd, 0x2f, 0xe5, 0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7,
+    0x58, 0x82, 0x8f, 0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b,
+    0x63, 0xd6, 0x10, 0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71,
+    0x1d, 0x97, 0x13, 0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e,
+    0xf3, 0x72, 0x51, 0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82,
+    0xff, 0xb5, 0xdc, 0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d,
+    0x0c, 0x3e, 0x99, 0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99,
+    0xe4, 0x39, 0xe0, 0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e,
+    0x7d, 0x09, 0x1e, 0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6,
+    0x55, 0x08, 0x0f, 0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c,
+    0x31, 0x4d, 0xf6, 0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7,
+    0x9e, 0xe9, 0x66, 0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23,
+    0x5b, 0x24, 0xf4, 0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef,
+    0x4b, 0xf9, 0x66, 0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6,
+    0x20, 0xa3, 0xec, 0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8,
+    0xf5, 0x84, 0x31, 0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47,
+    0x65, 0xc4, 0xe1, 0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc,
+    0xdc, 0x94, 0x7d, 0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf,
+    0xed, 0x77, 0x08, 0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43,
+    0x0f, 0xa6, 0x65, 0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79,
+    0x0e, 0x78, 0x36, 0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f,
+    0x42, 0x47, 0x99, 0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95,
+    0x42, 0x03, 0xec, 0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c,
+    0x53, 0x7d, 0x80, 0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7,
+    0xba, 0x59, 0x93, 0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6,
+    0xc9, 0x3d, 0x33, 0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2,
+    0xfe, 0x59, 0x8c, 0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88,
+    0x28, 0xfb, 0x21, 0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d,
+    0x61, 0x0c, 0x55, 0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9,
+    0x71, 0x38, 0x60, 0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37,
+    0x25, 0x1f, 0x51, 0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb,
+    0x5d, 0xc2, 0x08, 0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3,
+    0xe9, 0x99, 0x69, 0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43,
+    0x9e, 0x0d, 0xa8, 0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0,
+    0x91, 0xe6, 0x53, 0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50,
+    0x80, 0xfb, 0x04, 0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14,
+    0xdf, 0x60, 0x08, 0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee,
+    0x96, 0x64, 0xda, 0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2,
+    0x4f, 0x4c, 0xc4, 0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf,
+    0x96, 0x63, 0x34, 0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a,
+    0x3e, 0xc8, 0x55, 0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58,
+    0x43, 0x15, 0x7e, 0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c,
+    0x4e, 0x18, 0x3a, 0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9,
+    0x47, 0xd4, 0x74, 0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7,
+    0x70, 0x82, 0x38, 0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa,
+    0x66, 0x5a, 0x7a, 0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7,
+    0x83, 0x6a, 0x16, 0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24,
+    0x79, 0x94, 0xd1, 0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20,
+    0x3e, 0xc1, 0x0e, 0x23, 0xb2, 0xe2, 0x70, 0xc1, 0xd4, 0xb0, 0xc5, 0x37,
+    0xd8, 0x02, 0x0f, 0xde, 0x6e, 0x4a, 0x3e, 0xa3, 0xa7, 0x5e, 0x7b, 0xa5,
+    0x99, 0x36, 0x90, 0x5f, 0xf6, 0xbb, 0x84, 0x11, 0xc0, 0x8d, 0x6c, 0x93,
+    0xd3, 0x31, 0x0d, 0xa1, 0x87, 0xd3, 0x32, 0xd3, 0xd7, 0xbd, 0x2f, 0xe5,
+    0x98, 0xcd, 0x13, 0x3c, 0x87, 0x3c, 0x1b, 0x50, 0xb7, 0x58, 0x82, 0x8f,
+    0xb2, 0x15, 0x49, 0xcf, 0xa1, 0x23, 0xcc, 0xa6, 0x8b, 0x63, 0xd6, 0x10,
+    0xc5, 0x5f, 0xbc, 0xca, 0xa1, 0x01, 0xf6, 0x08, 0x71, 0x1d, 0x97, 0x13,
+    0x86, 0x0e, 0xa5, 0x86, 0x29, 0xbe, 0xc0, 0x10, 0x7e, 0xf3, 0x72, 0x51,
+    0xf5, 0x1d, 0x3a, 0xf3, 0xdd, 0x2c, 0xc9, 0xb4, 0x82, 0xff, 0xb5, 0xdc,
+    0x20, 0x8e, 0x04, 0x6b, 0x64, 0x9e, 0x99, 0x88, 0x6d, 0x0c, 0x3e, 0x99,
+    0x96, 0x9e, 0xbd, 0xe9, 0x7f, 0x2c, 0xc6, 0x68, 0x99, 0xe4, 0x39, 0xe0,
+    0xda, 0x85, 0xba, 0xc4, 0x14, 0x7d, 0x90, 0xaa, 0x4e, 0x7d, 0x09, 0x1e,
+    0x65, 0x34, 0x5b, 0x1e, 0xb0, 0x86, 0x2a, 0xfd, 0xe6, 0x55, 0x08, 0x0f,
+    0xb0, 0x43, 0x88, 0xec, 0xb8, 0x9c, 0x30, 0x75, 0x2c, 0x31, 0x4d, 0xf6,
+    0x00, 0x83, 0xf7, 0x9b, 0x92, 0x8f, 0xa8, 0xe9, 0xd7, 0x9e, 0xe9, 0x66,
+    0x4d, 0xa4, 0x17, 0xfd, 0xae, 0xe1, 0x04, 0x70, 0x23, 0x5b, 0x24, 0xf4,
+    0xcc, 0x43, 0x68, 0x61, 0xf4, 0xcc, 0xb4, 0xf5, 0xef, 0x4b, 0xf9, 0x66,
+    0x33, 0x44, 0xcf, 0x21, 0xcf, 0x06, 0xd4, 0x2d, 0xd6, 0x20, 0xa3, 0xec,
+    0x85, 0x52, 0x73, 0xe8, 0x48, 0xf3, 0x29, 0xa2, 0xd8, 0xf5, 0x84, 0x31,
+    0x57, 0xef, 0x32, 0xa8, 0x40, 0x7d, 0x82, 0x1c, 0x47, 0x65, 0xc4, 0xe1,
+    0x83, 0xa9, 0x61, 0x8a, 0x6f, 0xb0, 0x04, 0x1f, 0xbc, 0xdc, 0x94, 0x7d,
+    0x47, 0x4e, 0xbc, 0xf7, 0x4b, 0x32, 0x6d, 0x20, 0xbf, 0xed, 0x77, 0x08,
+    0x23, 0x81, 0x1a, 0xd9, 0x27, 0xa6, 0x62, 0x1b, 0x43, 0x0f, 0xa6, 0x65,
+    0xa7, 0xaf, 0x7a, 0x5f, 0xcb, 0x31, 0x9a, 0x26, 0x79, 0x0e, 0x78, 0x36,
+    0xa1, 0x6e, 0xb1, 0x05, 0x1f, 0x64, 0x2a, 0x93, 0x9f, 0x42, 0x47, 0x99,
+    0x4d, 0x16, 0xc7, 0xac, 0x21, 0x8a, 0xbf, 0x79, 0x95, 0x42, 0x03, 0xec,
+    0x10, 0xe2, 0x3b, 0x2e, 0x27, 0x0c, 0x1d, 0x4b, 0x0c, 0x53, 0x7d, 0x80,
+    0x20, 0xfd, 0xe6, 0xe4, 0xa3, 0xea, 0x3a, 0x75, 0xe7, 0xba, 0x59, 0x93,
+    0x69, 0x05, 0xff, 0x6b, 0xb8, 0x41, 0x1c, 0x08, 0xd6, 0xc9, 0x3d, 0x33,
+    0x10, 0xda, 0x18, 0x7d, 0x33, 0x2d, 0x3d, 0x7b, 0xd2, 0xfe, 0x59, 0x8c,
+    0xd1, 0x33, 0xc8, 0x73, 0xc1, 0xb5, 0x0b, 0x75, 0x88, 0x28, 0xfb, 0x21,
+    0x54, 0x9c, 0xfa, 0x12, 0x3c, 0xca, 0x68, 0xb6, 0x3d, 0x61, 0x0c, 0x55,
+    0xfb, 0xcc, 0xaa, 0x10, 0x1f, 0x60, 0x87, 0x11, 0xd9, 0x71, 0x38, 0x60,
+    0xea, 0x58, 0x62, 0x9b, 0xec, 0x01, 0x07, 0xef, 0x37, 0x25, 0x1f, 0x51,
+    0xd3, 0xaf, 0x3d, 0xd2, 0xcc, 0x9b, 0x48, 0x2f, 0xfb, 0x5d, 0xc2, 0x08,
+    0xe0, 0x46, 0xb6, 0x49, 0xe9, 0x98, 0x86, 0xd0, 0xc3, 0xe9, 0x99, 0x69,
+    0xeb, 0xde, 0x97, 0xf2, 0xcc, 0x66, 0x89, 0x9e, 0x43, 0x9e, 0x0d, 0xa8,
+    0x5b, 0xac, 0x41, 0x47, 0xd9, 0x0a, 0xa4, 0xe7, 0xd0, 0x91, 0xe6, 0x53,
+    0x45, 0xb1, 0xeb, 0x08, 0x62, 0xaf, 0xde, 0x65, 0x50, 0x80, 0xfb, 0x04,
+    0x38, 0x8e, 0xcb, 0x89, 0xc3, 0x07, 0x52, 0xc3, 0x14, 0xdf, 0x60, 0x08,
+    0x3f, 0x79, 0xb9, 0x28, 0xfa, 0x8e, 0x9d, 0x79, 0xee, 0x96, 0x64, 0xda,
+    0x41, 0x7f, 0xda, 0xee, 0x10, 0x47, 0x02, 0x35, 0xb2, 0x4f, 0x4c, 0xc4,
+    0x36, 0x86, 0x1f, 0x4c, 0xcb, 0x4f, 0x5e, 0xf4, 0xbf, 0x96, 0x63, 0x34,
+    0x4c, 0xf2, 0x1c, 0xf0, 0x6d, 0x42, 0xdd, 0x62, 0x0a, 0x3e, 0xc8, 0x55,
+    0x27, 0x3e, 0x84, 0x8f, 0x32, 0x9a, 0x2d, 0x8f, 0x58, 0x43, 0x15, 0x7e,
+    0xf3, 0x2a, 0x84, 0x07, 0xd8, 0x21, 0xc4, 0x76, 0x5c, 0x4e, 0x18, 0x3a,
+    0x96, 0x18, 0xa6, 0xfb, 0x00, 0x41, 0xfb, 0xcd, 0xc9, 0x47, 0xd4, 0x74,
+    0xeb, 0xcf, 0x74, 0xb3, 0x26, 0xd2, 0x0b, 0xfe, 0xd7, 0x70, 0x82, 0x38,
+    0x11, 0xad, 0x92, 0x7a, 0x66, 0x21, 0xb4, 0x30, 0xfa, 0x66, 0x5a, 0x7a,
+    0xf7, 0xa5, 0xfc, 0xb3, 0x19, 0xa2, 0x67, 0x90, 0xe7, 0x83, 0x6a, 0x16,
+    0xeb, 0x10, 0x51, 0xf6, 0x42, 0xa9, 0x39, 0xf4, 0x24, 0x79, 0x94, 0xd1,
+    0x6c, 0x7a, 0xc2, 0x18, 0xab, 0xf7, 0x99, 0x54, 0x20, 0x3e, 0xc1, 0x0e,
+    0x23, 0xb3,
+};
+static_assert(sizeof(kBytesTestReadSymbol7) == kNumBytesTestReadSymbol7, "");
+
+// The kBytesTestReadSymbol8[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][9] = {
+//   // pdf: 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8, 1/8
+//   { 32768 - 4096, 32768 - 8192, 32768 - 12288, 32768 - 16384,
+//     32768 - 20480, 32768 - 24576, 32768 - 28672, 0, 0 },
+//   // pdf: 3/16, 2/16, 2/16, 2/16, 2/16, 2/16, 2/16, 1/16
+//   { 32768 - 6144, 32768 - 10240, 32768 - 14336, 32768 - 18432,
+//     32768 - 22528, 32768 - 26624, 32768 - 30720, 0, 0 },
+//   // pdf: 1/16, 1/16, 2/16, 2/16, 2/16, 2/16, 3/16, 3/16
+//   { 32768 - 2048, 32768 - 4096, 32768 - 8192, 32768 - 12288,
+//     32768 - 16384, 32768 - 20480, 32768 - 26624, 0, 0 },
+//   // pdf: 1/16, 1/16, 3/16, 3/16, 3/16, 3/16, 1/16, 1/16
+//   { 32768 - 2048, 32768 - 4096, 32768 - 10240, 32768 - 16384,
+//     32768 - 22528, 32768 - 28672, 32768 - 30720, 0, 0 },
+// };
+// constexpr int kSymbols[16][4] = { { 0, 4, 7, 3 },  //
+//                                   { 1, 5, 6, 2 },  //
+//                                   { 2, 6, 5, 1 },  //
+//                                   { 3, 7, 4, 0 },  //
+//                                   { 4, 0, 3, 7 },  //
+//                                   { 5, 1, 2, 6 },  //
+//                                   { 6, 2, 1, 5 },  //
+//                                   { 7, 3, 0, 4 },  //
+//                                   { 0, 0, 6, 5 },  //
+//                                   { 2, 1, 4, 3 },  //
+//                                   { 4, 3, 6, 4 },  //
+//                                   { 6, 5, 2, 2 },  //
+//                                   { 1, 0, 7, 3 },  //
+//                                   { 3, 2, 5, 5 },  //
+//                                   { 5, 4, 7, 2 },  //
+//                                   { 7, 6, 3, 4 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 1024; ++i) {
+//   for (int j = 0; j < 16; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 8);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("  constexpr size_t kNumBytesTestReadSymbol8 = %u;\n", bw.pos);
+// printf("  constexpr uint8_t kBytesTestReadSymbol8[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n      ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n  };\n");
+
+constexpr size_t kNumBytesTestReadSymbol8 = 24195;
+constexpr uint8_t kBytesTestReadSymbol8[] = {
+    0x15, 0x60, 0xa8, 0x52, 0xf4, 0x88, 0xdd, 0x23, 0x40, 0xb1, 0xd6, 0xd2,
+    0xc2, 0xa2, 0x4c, 0x0a, 0x5d, 0xba, 0xfe, 0xd2, 0x36, 0xd9, 0xcd, 0x51,
+    0x10, 0x25, 0x13, 0x29, 0xfa, 0x0d, 0x87, 0xf9, 0xd1, 0x6f, 0xf2, 0x0d,
+    0x3a, 0xbe, 0xd9, 0x83, 0x99, 0xd1, 0xdf, 0x24, 0x70, 0x28, 0xdb, 0x63,
+    0xf6, 0x7c, 0x07, 0x2b, 0x68, 0xa3, 0x7a, 0x85, 0xd1, 0x47, 0xba, 0x59,
+    0x18, 0x7e, 0x64, 0x3b, 0xac, 0xaf, 0xe3, 0x3a, 0x99, 0x82, 0x30, 0x92,
+    0x7a, 0x93, 0x67, 0x9f, 0xac, 0x53, 0xf8, 0xdb, 0x03, 0x71, 0xc7, 0x4a,
+    0xa9, 0xec, 0x10, 0xc9, 0xed, 0x5b, 0xa6, 0xd5, 0xc3, 0xdd, 0x81, 0x8d,
+    0x25, 0xbe, 0x57, 0xcd, 0x01, 0x65, 0x33, 0x6c, 0x12, 0xe1, 0x37, 0x8b,
+    0xf1, 0x08, 0x27, 0x3c, 0x5a, 0x30, 0x9f, 0x2d, 0x41, 0x2e, 0x75, 0x49,
+    0xab, 0xa6, 0xb6, 0x4c, 0xbe, 0xe0, 0xd0, 0x20, 0x74, 0xeb, 0x05, 0x79,
+    0x91, 0x60, 0xfd, 0xb2, 0x39, 0x54, 0xd9, 0x0c, 0x11, 0x04, 0x1f, 0x7b,
+    0x5d, 0x2d, 0xe3, 0x3f, 0x48, 0xe4, 0x56, 0x11, 0x3d, 0x48, 0xdb, 0x5c,
+    0x1c, 0x8b, 0x81, 0xbb, 0x8a, 0x53, 0xb7, 0x48, 0x5b, 0x15, 0x9b, 0x35,
+    0xc1, 0x18, 0x0f, 0xc3, 0x1e, 0x1c, 0x16, 0x7e, 0x0a, 0xbf, 0x16, 0x0a,
+    0xf5, 0x3f, 0xbe, 0x19, 0xc0, 0x0f, 0xa4, 0x59, 0xae, 0x0a, 0xcf, 0xf4,
+    0x00, 0xb2, 0xff, 0x3a, 0xd8, 0x7f, 0x6c, 0xcf, 0x4f, 0xca, 0xa1, 0x40,
+    0x47, 0x8e, 0xd0, 0x44, 0x49, 0x5a, 0x48, 0xe6, 0x86, 0x80, 0xbb, 0x57,
+    0x36, 0x6e, 0x80, 0xf1, 0xd1, 0xd8, 0xb8, 0xad, 0xb7, 0x6b, 0x11, 0x79,
+    0x02, 0x95, 0x20, 0xcf, 0x6f, 0x21, 0xe6, 0x5c, 0x65, 0x69, 0x4a, 0xf2,
+    0x6f, 0x87, 0x68, 0xf1, 0xda, 0x3b, 0xe1, 0x64, 0x5c, 0xfc, 0x21, 0x02,
+    0x7b, 0xf6, 0x39, 0x77, 0x36, 0x29, 0x3d, 0xda, 0x16, 0x2e, 0xdb, 0x55,
+    0xac, 0x5a, 0x3a, 0x94, 0x9c, 0x79, 0x2c, 0x92, 0xa4, 0xe3, 0xe2, 0x87,
+    0xd8, 0x14, 0x21, 0x76, 0xae, 0xf1, 0x8d, 0x7d, 0xdc, 0xde, 0x46, 0xd9,
+    0xbd, 0xb6, 0x5f, 0xae, 0x77, 0xd0, 0xd7, 0x01, 0xed, 0xbe, 0x5f, 0xee,
+    0x1a, 0x20, 0x0f, 0x88, 0x5c, 0x8a, 0x44, 0xad, 0x8f, 0x8f, 0x66, 0x9d,
+    0x43, 0xf4, 0x41, 0x0a, 0xa1, 0xc8, 0x5c, 0xbc, 0x37, 0xe2, 0xca, 0xd2,
+    0xd8, 0x27, 0x54, 0xdb, 0xdf, 0x7f, 0x0a, 0xd7, 0x65, 0x19, 0x99, 0x1a,
+    0x92, 0x53, 0xdd, 0x1e, 0x5f, 0xad, 0x24, 0x8a, 0x8d, 0x76, 0xc4, 0xf7,
+    0x7e, 0x74, 0xfe, 0x68, 0x99, 0x42, 0xfa, 0xaa, 0x6e, 0xdd, 0x91, 0xd4,
+    0x71, 0x10, 0xb7, 0x45, 0xa8, 0x5f, 0x84, 0x0d, 0xeb, 0x38, 0x3e, 0xaa,
+    0xf1, 0xad, 0x86, 0x8f, 0x1a, 0x3e, 0x9a, 0x29, 0xc7, 0x7b, 0xa7, 0xdf,
+    0x51, 0x3d, 0x49, 0x08, 0x09, 0x69, 0x40, 0x9d, 0x45, 0xb8, 0x55, 0xce,
+    0x96, 0x6c, 0x8b, 0xc6, 0xc9, 0x25, 0x70, 0xc9, 0xb3, 0xa8, 0xa8, 0x08,
+    0x33, 0x7b, 0xca, 0x21, 0x9e, 0x5b, 0xb5, 0x02, 0x7f, 0xa3, 0x34, 0x7c,
+    0x3d, 0xba, 0x91, 0x2e, 0xae, 0xc3, 0x1f, 0x9e, 0xc2, 0x4f, 0xdf, 0xa9,
+    0x39, 0x9b, 0x9d, 0x6e, 0xc7, 0x90, 0xeb, 0x2b, 0xb0, 0x3f, 0xde, 0x37,
+    0xb7, 0x94, 0x3d, 0x4b, 0x2c, 0x42, 0x3f, 0x47, 0xad, 0xc9, 0x23, 0xcb,
+    0x4d, 0xc4, 0xdd, 0x5e, 0x67, 0x11, 0x9d, 0x45, 0xb8, 0x55, 0xce, 0x98,
+    0x05, 0xce, 0x97, 0x99, 0x57, 0x84, 0x8d, 0x79, 0x97, 0x81, 0x4b, 0x8a,
+    0x9c, 0x76, 0x73, 0x9a, 0xf7, 0x59, 0x54, 0x07, 0x6c, 0x11, 0x41, 0x44,
+    0xf0, 0xa6, 0x2a, 0x5e, 0xb1, 0x48, 0x47, 0x39, 0xbb, 0x1b, 0xf0, 0x25,
+    0x07, 0xe7, 0xd2, 0xbb, 0x9b, 0x9b, 0xd7, 0x7e, 0xc8, 0xdd, 0xae, 0xb6,
+    0x23, 0x5e, 0xe0, 0xa5, 0xb0, 0xc6, 0xb6, 0x81, 0xe9, 0x51, 0x20, 0xe9,
+    0x2f, 0x89, 0xcd, 0x13, 0x96, 0x21, 0x19, 0xc5, 0xd1, 0x65, 0x65, 0x88,
+    0xd9, 0x7b, 0x87, 0xdc, 0xfb, 0x38, 0x54, 0x22, 0x27, 0xc4, 0xc4, 0x16,
+    0x56, 0xff, 0x76, 0x69, 0xa6, 0x3b, 0xa0, 0x6d, 0xab, 0xb8, 0xdf, 0xc1,
+    0xc2, 0xff, 0x65, 0x8f, 0x85, 0xbc, 0x69, 0xc0, 0xa5, 0x9a, 0xef, 0xf1,
+    0x37, 0x57, 0x99, 0xc4, 0x67, 0x51, 0x6e, 0xdf, 0x30, 0xa4, 0x86, 0x47,
+    0x34, 0x5f, 0x5e, 0x3c, 0xde, 0x6e, 0x96, 0x74, 0x5c, 0xbd, 0xca, 0xa3,
+    0x50, 0xe4, 0xe8, 0x63, 0xdf, 0xb0, 0xf1, 0xbe, 0xa2, 0x58, 0x23, 0x7a,
+    0x4a, 0x29, 0x62, 0x1f, 0x03, 0xf1, 0xe9, 0x19, 0xdd, 0x68, 0xe8, 0x1a,
+    0x7a, 0x9b, 0x40, 0x0d, 0xb0, 0x15, 0x8b, 0x14, 0x63, 0x08, 0xa4, 0x21,
+    0xa6, 0x0b, 0x34, 0x8a, 0x3e, 0x76, 0x7a, 0xa8, 0x11, 0x81, 0x16, 0x12,
+    0xa5, 0xc6, 0x7a, 0xf1, 0xa0, 0x20, 0xff, 0x33, 0x3b, 0xa5, 0x43, 0xc7,
+    0x42, 0xd3, 0x22, 0x90, 0x16, 0xa2, 0x28, 0x18, 0xa4, 0xc7, 0x24, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22,
+    0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93,
+    0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15,
+    0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b,
+    0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab,
+    0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf,
+    0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58,
+    0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd,
+    0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3,
+    0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8,
+    0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f,
+    0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41,
+    0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe,
+    0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b,
+    0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3,
+    0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59,
+    0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99,
+    0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8,
+    0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc,
+    0x02, 0x45, 0x04, 0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42,
+    0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60,
+    0x12, 0x28, 0x20, 0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15,
+    0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00,
+    0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae,
+    0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04,
+    0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73,
+    0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24,
+    0x50, 0x40, 0x63, 0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99,
+    0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22,
+    0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf,
+    0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14,
+    0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f,
+    0x52, 0xf5, 0xee, 0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0,
+    0x80, 0xc6, 0x63, 0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa,
+    0x97, 0xaf, 0x75, 0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04,
+    0x06, 0x33, 0x1d, 0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4,
+    0xbd, 0x7b, 0xae, 0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20,
+    0x31, 0x98, 0xeb, 0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5,
+    0xeb, 0xdd, 0x74, 0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01,
+    0x8c, 0xc7, 0x5e, 0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f,
+    0x5e, 0xeb, 0xa3, 0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c,
+    0x66, 0x3a, 0xf1, 0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a,
+    0xf7, 0x5d, 0x1c, 0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63,
+    0x31, 0xd7, 0x88, 0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7,
+    0xba, 0xe8, 0xe4, 0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19,
+    0x8e, 0xbc, 0x46, 0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd,
+    0xd7, 0x47, 0x24, 0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc,
+    0x75, 0xe2, 0x32, 0x6f, 0xd0, 0x59, 0x0a, 0xe6, 0x7f, 0x52, 0xf5, 0xee,
+    0xba, 0x39, 0x22, 0xac, 0x3f, 0x99, 0x80, 0x48, 0xa0, 0x80, 0xc6, 0x63,
+    0xaf, 0x11, 0x93, 0x7e, 0x82, 0xc8, 0x57, 0x33, 0xfa, 0x97, 0xaf, 0x75,
+    0xd1, 0xc9, 0x15, 0x61, 0xfc, 0xcc, 0x02, 0x45, 0x04, 0x06, 0x33, 0x1d,
+    0x78, 0x8c, 0x9b, 0xf4, 0x16, 0x42, 0xb9, 0x9f, 0xd4, 0xbd, 0x7b, 0xae,
+    0x8e, 0x48, 0xab, 0x0f, 0xe6, 0x60, 0x12, 0x28, 0x20, 0x31, 0x98, 0xeb,
+    0xc4, 0x64, 0xdf, 0xa0, 0xb2, 0x15, 0xcc, 0xfe, 0xa5, 0xeb, 0xdd, 0x74,
+    0x72, 0x45, 0x58, 0x7f, 0x33, 0x00, 0x91, 0x41, 0x01, 0x8c, 0xc7, 0x5e,
+    0x23, 0x26, 0xfd, 0x05, 0x90, 0xae, 0x67, 0xf5, 0x2f, 0x5e, 0xeb, 0xa3,
+    0x92, 0x2a, 0xc3, 0xf9, 0x98, 0x04, 0x8a, 0x08, 0x0c, 0x66, 0x3a, 0xf1,
+    0x19, 0x37, 0xe8, 0x2c, 0x85, 0x73, 0x3f, 0xa9, 0x7a, 0xf7, 0x5d, 0x1c,
+    0x91, 0x56, 0x1f, 0xcc, 0xc0, 0x24, 0x50, 0x40, 0x63, 0x31, 0xd7, 0x88,
+    0xc9, 0xbf, 0x41, 0x64, 0x2b, 0x99, 0xfd, 0x4b, 0xd7, 0xba, 0xe8, 0xe4,
+    0x8a, 0xb0, 0xfe, 0x66, 0x01, 0x22, 0x82, 0x03, 0x19, 0x8e, 0xbc, 0x46,
+    0x4d, 0xfa, 0x0b, 0x21, 0x5c, 0xcf, 0xea, 0x5e, 0xbd, 0xd7, 0x47, 0x24,
+    0x55, 0x87, 0xf3, 0x30, 0x09, 0x14, 0x10, 0x18, 0xcc, 0x75, 0xe2, 0x32,
+    0x6f, 0xd0, 0xc0,
+};
+static_assert(sizeof(kBytesTestReadSymbol8) == kNumBytesTestReadSymbol8, "");
+
+// The kBytesTestReadSymbol9[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][10] = {
+//   // pmf: 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9
+//   { 32768 - 3641, 32768 - 7282, 32768 - 10923, 32768 - 14564, 32768 - 18204,
+//     32768 - 21845, 32768 - 25486, 32768 - 29127, 0, 0 },
+//   // pmf: 3/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 1/18
+//   { 32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 16384, 32768 - 20025,
+//     32768 - 23666, 32768 - 27307, 32768 - 30948, 0, 0 },
+//   // pmf: 1/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 2/18, 3/18
+//   { 32768 - 1820, 32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 16384,
+//     32768 - 20025, 32768 - 23666, 32768 - 27307, 0, 0 },
+//   // pmf: 1/18, 2/18, 2/18, 2/18, 4/18, 2/18, 2/18, 2/18, 1/18
+//   { 32768 - 1820, 32768 - 5461, 32768 - 9102, 32768 - 12743, 32768 - 20025,
+//     32768 - 23666, 32768 - 27307, 32768 - 30948, 0, 0 },
+// };
+// constexpr int kSymbols[18][4] = { { 0, 4, 8, 3 },  //
+//                                   { 1, 5, 7, 2 },  //
+//                                   { 2, 6, 6, 1 },  //
+//                                   { 3, 7, 5, 0 },  //
+//                                   { 4, 8, 4, 8 },  //
+//                                   { 5, 0, 3, 7 },  //
+//                                   { 6, 1, 2, 6 },  //
+//                                   { 7, 2, 1, 5 },  //
+//                                   { 8, 3, 0, 4 },  //
+//                                   { 0, 0, 8, 7 },  //
+//                                   { 2, 1, 6, 5 },  //
+//                                   { 4, 3, 4, 3 },  //
+//                                   { 6, 5, 2, 1 },  //
+//                                   { 8, 7, 7, 6 },  //
+//                                   { 1, 0, 5, 4 },  //
+//                                   { 3, 2, 3, 2 },  //
+//                                   { 5, 4, 1, 4 },  //
+//                                   { 7, 6, 8, 4 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 128; ++i) {
+//   for (int j = 0; j < 18; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 9);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol9 = 3650;
+constexpr uint8_t kBytesTestReadSymbol9[] = {
+    0x10, 0xe6, 0x62, 0x17, 0x4c, 0x5e, 0xe0, 0x8c, 0x41, 0x75, 0x38, 0xda,
+    0xb6, 0x33, 0xc7, 0x0e, 0x0f, 0x62, 0x87, 0x29, 0xbe, 0x28, 0x8b, 0x81,
+    0x71, 0xab, 0x0d, 0xfe, 0x61, 0xf9, 0x96, 0x85, 0xfe, 0x78, 0x18, 0xe6,
+    0x57, 0xa7, 0xf0, 0xd3, 0xd5, 0x62, 0x37, 0x9a, 0x3d, 0xc4, 0xad, 0x75,
+    0x35, 0xc1, 0xe9, 0x63, 0xeb, 0x9c, 0xd3, 0xf4, 0xdb, 0xc0, 0xf3, 0x67,
+    0x14, 0xbd, 0xde, 0xf7, 0xd1, 0x51, 0xf1, 0x62, 0x28, 0xd5, 0x39, 0x99,
+    0x82, 0x5b, 0x9c, 0x3a, 0x37, 0x85, 0xe7, 0x48, 0x28, 0x02, 0x2d, 0xf1,
+    0x15, 0x55, 0x77, 0x02, 0x2e, 0x62, 0x53, 0xf6, 0x8a, 0x53, 0x44, 0xfa,
+    0xe0, 0xff, 0x05, 0xae, 0xdc, 0x30, 0xee, 0x36, 0x29, 0x80, 0xd5, 0x0a,
+    0xa6, 0x5f, 0x53, 0xa2, 0x31, 0xc0, 0x5b, 0x2a, 0xa5, 0xa5, 0xd2, 0xc0,
+    0x8d, 0x96, 0x66, 0x25, 0x93, 0x9e, 0xdc, 0x0b, 0x2f, 0xea, 0xe2, 0x51,
+    0x0b, 0x12, 0x87, 0x90, 0x79, 0xe7, 0x8e, 0x6f, 0xc6, 0x99, 0x4b, 0x6a,
+    0x50, 0x06, 0xf3, 0x3d, 0xf5, 0x25, 0x72, 0xc5, 0x9e, 0xab, 0x7b, 0x5b,
+    0x15, 0xf5, 0xeb, 0xae, 0x02, 0xe4, 0x90, 0x2b, 0x15, 0x66, 0xf7, 0x50,
+    0xfa, 0x46, 0x74, 0xae, 0xd4, 0x7f, 0xd4, 0x0b, 0xbf, 0xbc, 0x83, 0x60,
+    0x6f, 0x25, 0x87, 0xde, 0xce, 0xb3, 0x86, 0x5a, 0x13, 0x00, 0x31, 0xf2,
+    0x75, 0xca, 0x08, 0x71, 0xd2, 0xf4, 0xa9, 0xf9, 0x40, 0x23, 0xa7, 0x5e,
+    0x50, 0x63, 0x64, 0x1d, 0xa2, 0x50, 0x2f, 0x01, 0x4c, 0x11, 0x8b, 0xcb,
+    0x92, 0x40, 0x9d, 0x94, 0x50, 0x0a, 0xf5, 0x3b, 0xfc, 0x32, 0x1a, 0xbd,
+    0x48, 0x73, 0xe7, 0x93, 0x0f, 0x53, 0xb2, 0x8e, 0xac, 0xef, 0x22, 0x2f,
+    0x3e, 0xb0, 0x81, 0xc0, 0x06, 0x9b, 0x14, 0x5c, 0xa6, 0x16, 0xca, 0xa5,
+    0x79, 0xd2, 0x6a, 0xd3, 0xfe, 0x93, 0x33, 0x2f, 0xdb, 0xcb, 0xca, 0xb3,
+    0x1d, 0xc5, 0x56, 0x65, 0x53, 0x7f, 0xb9, 0x41, 0xe1, 0x54, 0x31, 0xa2,
+    0x8c, 0x92, 0xc8, 0x04, 0xf7, 0x9d, 0x26, 0xad, 0x35, 0x00, 0x5a, 0xb2,
+    0x78, 0x43, 0x14, 0xc2, 0xeb, 0x3a, 0x26, 0x4d, 0x49, 0x5d, 0x33, 0xe4,
+    0xa9, 0xea, 0xd3, 0x67, 0xbf, 0xbc, 0xb6, 0x2e, 0x1c, 0xf7, 0xd0, 0x98,
+    0x13, 0x0d, 0x7c, 0x94, 0x02, 0x28, 0x3e, 0x8a, 0xe5, 0x0c, 0x75, 0x82,
+    0xe5, 0x81, 0x98, 0x87, 0x88, 0x97, 0x86, 0xd6, 0x46, 0x2c, 0x9c, 0x85,
+    0xc2, 0x99, 0xfd, 0x0a, 0x68, 0xbf, 0x67, 0xfc, 0x17, 0xc7, 0x11, 0x54,
+    0xd1, 0x20, 0x9d, 0x83, 0x52, 0x84, 0x5d, 0x4b, 0x62, 0xbf, 0x16, 0x5d,
+    0x8e, 0x72, 0x46, 0xde, 0xb1, 0x77, 0xfb, 0x39, 0x98, 0xf0, 0x4d, 0xa6,
+    0x7a, 0x7d, 0x1c, 0x16, 0xe9, 0x1e, 0x86, 0x7e, 0xf9, 0x22, 0x58, 0x93,
+    0xea, 0x2e, 0x26, 0xc7, 0xfb, 0xd1, 0xb3, 0xc7, 0x99, 0xb1, 0x91, 0x67,
+    0xf1, 0xa3, 0xe0, 0xd2, 0xe8, 0x17, 0x17, 0xd7, 0x0b, 0x7a, 0xd4, 0xed,
+    0x9e, 0x72, 0x4e, 0xa2, 0x37, 0xc9, 0xd2, 0x16, 0x5d, 0x8b, 0xda, 0xdb,
+    0x5c, 0x46, 0x05, 0x3e, 0xf7, 0xc8, 0x3a, 0xd5, 0xaf, 0xd9, 0x72, 0x82,
+    0xbf, 0x96, 0xea, 0x09, 0xd3, 0xd5, 0xfe, 0x43, 0x24, 0xae, 0x95, 0x3d,
+    0x6c, 0x68, 0x54, 0xad, 0xb5, 0xc4, 0x60, 0x54, 0x08, 0x3c, 0x57, 0x61,
+    0xa1, 0x11, 0x21, 0x7f, 0xca, 0x48, 0x59, 0xb4, 0x1c, 0x39, 0x0d, 0xf2,
+    0xdc, 0x62, 0xf0, 0xbb, 0x95, 0x39, 0x51, 0xe9, 0xdb, 0xf1, 0x5d, 0xd1,
+    0x43, 0x83, 0x8a, 0xb1, 0x8d, 0x36, 0x39, 0x83, 0xc6, 0x94, 0x30, 0xbe,
+    0xb6, 0x2f, 0x39, 0x05, 0xad, 0xcd, 0xf9, 0x4c, 0xc2, 0x34, 0xc7, 0x81,
+    0x68, 0xb1, 0x20, 0x1d, 0xea, 0xd3, 0x8c, 0xca, 0xff, 0x4d, 0x94, 0xe1,
+    0x3e, 0xc2, 0x74, 0x90, 0xed, 0x56, 0x3c, 0x1b, 0x5b, 0xf6, 0x40, 0xf9,
+    0x3b, 0x94, 0x94, 0x23, 0xc6, 0x48, 0x6a, 0x59, 0xef, 0x04, 0xb7, 0x9f,
+    0x55, 0x9c, 0x6f, 0x81, 0x73, 0xec, 0x27, 0x49, 0x0e, 0xd5, 0x63, 0xc1,
+    0xb5, 0xbf, 0x64, 0x0f, 0x93, 0xb9, 0x49, 0x42, 0x3c, 0x64, 0x86, 0xa5,
+    0x9e, 0xf0, 0x4b, 0x79, 0xf5, 0x59, 0xc7, 0xc5, 0x01, 0x6f, 0xbd, 0x6a,
+    0x66, 0x93, 0x99, 0x47, 0xb6, 0xf7, 0xfa, 0x21, 0x72, 0x81, 0x71, 0x40,
+    0x36, 0x81, 0xde, 0x5d, 0xdf, 0xdf, 0x30, 0x53, 0x03, 0x70, 0xfb, 0xb2,
+    0x2d, 0x37, 0xeb, 0x19, 0xbc, 0xd2, 0x90, 0x44, 0x25, 0x42, 0x06, 0x30,
+    0xc8, 0xcf, 0x4b, 0x0a, 0x01, 0x13, 0x5e, 0x17, 0x91, 0xc7, 0xcb, 0x79,
+    0xed, 0x06, 0x39, 0xc1, 0x2e, 0x92, 0x29, 0xf5, 0xff, 0x24, 0xe7, 0x2b,
+    0x3f, 0x19, 0x35, 0x6b, 0x3d, 0x69, 0xa2, 0x19, 0x20, 0x53, 0xd4, 0xca,
+    0x08, 0x35, 0x6e, 0xe0, 0x5a, 0x9a, 0x9d, 0x48, 0xf5, 0x20, 0x24, 0x20,
+    0x33, 0x94, 0x6b, 0x33, 0xdd, 0x78, 0xbf, 0x62, 0xf1, 0x43, 0x08, 0x97,
+    0x53, 0x98, 0xe4, 0x17, 0x27, 0xfc, 0xe8, 0xf1, 0xb8, 0x4c, 0xb3, 0x79,
+    0xc8, 0x05, 0x21, 0x1b, 0xe8, 0x56, 0xd2, 0x5f, 0xb6, 0x90, 0x14, 0x0c,
+    0x96, 0x38, 0xc6, 0xc3, 0x6d, 0x10, 0xbf, 0xc6, 0x28, 0xfe, 0x1f, 0x13,
+    0x81, 0x04, 0xeb, 0x37, 0x9c, 0x80, 0x52, 0x47, 0x0f, 0xa0, 0x6e, 0xcd,
+    0x9c, 0x44, 0xdd, 0x61, 0x9c, 0x8f, 0xb2, 0xf5, 0xe0, 0xa0, 0x2b, 0x2f,
+    0xe7, 0x67, 0xd0, 0xd7, 0x29, 0x08, 0x72, 0xee, 0xd5, 0x60, 0xb9, 0xbb,
+    0x1b, 0x12, 0xce, 0x60, 0x98, 0xb9, 0x40, 0xd3, 0xd9, 0x77, 0x5d, 0x6b,
+    0x78, 0xaa, 0x9a, 0x47, 0x2a, 0xf5, 0x38, 0xbb, 0xbe, 0x3a, 0x82, 0x6a,
+    0xbf, 0x8b, 0x67, 0x7e, 0xa4, 0x78, 0xbf, 0xcf, 0x58, 0xce, 0x86, 0x2e,
+    0x34, 0xb7, 0x76, 0x99, 0xa5, 0xf1, 0x0c, 0xa9, 0x1c, 0x9f, 0xad, 0xcb,
+    0xac, 0xf4, 0x03, 0x60, 0xe0, 0x22, 0xfe, 0x02, 0x34, 0x9a, 0x14, 0xb9,
+    0x11, 0xea, 0x4c, 0x3a, 0x59, 0xaa, 0xec, 0x8f, 0x82, 0x49, 0x23, 0xa2,
+    0xd0, 0xf7, 0xc3, 0xf0, 0xaa, 0x2d, 0xb2, 0xb8, 0xce, 0x02, 0x2f, 0xe0,
+    0x23, 0x49, 0xa1, 0x38, 0x12, 0xba, 0xab, 0x9f, 0x60, 0xe4, 0x0d, 0xfa,
+    0x2b, 0xcc, 0xad, 0x6a, 0x06, 0xca, 0x38, 0x82, 0xc5, 0x88, 0x10, 0xb6,
+    0xf5, 0xf6, 0x06, 0x7b, 0x03, 0x9c, 0xe4, 0x89, 0xaf, 0xdb, 0x66, 0x45,
+    0xeb, 0x2c, 0x28, 0xe2, 0x40, 0x08, 0x44, 0xe2, 0x8a, 0x91, 0x19, 0x04,
+    0x29, 0x46, 0xa7, 0xb5, 0x78, 0xae, 0x05, 0xcc, 0x38, 0x9f, 0xd8, 0x58,
+    0xc9, 0x79, 0xf9, 0xad, 0x77, 0x66, 0x49, 0x62, 0xef, 0x13, 0x72, 0xee,
+    0xda, 0x37, 0xb5, 0xd7, 0xf1, 0x51, 0x5d, 0x16, 0x11, 0xf3, 0x91, 0xf2,
+    0x13, 0x49, 0x09, 0x50, 0x15, 0xc6, 0x48, 0xe6, 0xe9, 0x4c, 0xf0, 0x06,
+    0x14, 0x3f, 0xef, 0x46, 0x15, 0xaf, 0x96, 0x0d, 0x17, 0x51, 0x08, 0xf2,
+    0xe1, 0xc9, 0xb9, 0x1d, 0x8d, 0x8f, 0x74, 0x25, 0x04, 0x1f, 0x2c, 0x62,
+    0x67, 0xe4, 0x4b, 0xdc, 0x67, 0x39, 0x2c, 0x7d, 0x3a, 0x1e, 0x6f, 0x5b,
+    0x0b, 0xab, 0x0b, 0x1f, 0x64, 0x37, 0x19, 0x4f, 0x6b, 0x07, 0x05, 0xff,
+    0x6e, 0x89, 0x8f, 0x22, 0x7d, 0x28, 0xd9, 0x3b, 0x9a, 0xe2, 0x3f, 0xff,
+    0xc2, 0xb1, 0xca, 0x05, 0xbc, 0x05, 0xa5, 0xe7, 0x2d, 0x66, 0xf7, 0x37,
+    0x92, 0xd2, 0xb4, 0x35, 0x26, 0x3f, 0x8c, 0x0c, 0x22, 0xa5, 0x5f, 0x5e,
+    0x9c, 0x01, 0x46, 0x91, 0xe7, 0xa2, 0x92, 0x97, 0x0a, 0x19, 0x85, 0x2f,
+    0x54, 0xe3, 0xa8, 0x26, 0xab, 0xe6, 0xb5, 0xd9, 0x71, 0x19, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd,
+    0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f,
+    0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e,
+    0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe,
+    0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69,
+    0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83,
+    0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e,
+    0x00, 0xac, 0x09, 0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7,
+    0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e,
+    0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41,
+    0x11, 0xea, 0x4b, 0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb,
+    0x0b, 0xe2, 0x7d, 0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09,
+    0x06, 0x99, 0x9b, 0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8,
+    0xf8, 0x39, 0xb8, 0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03,
+    0x60, 0xe0, 0x0a, 0xc0, 0x90, 0x69, 0x99, 0xb7, 0x41, 0x11, 0xea, 0x4b,
+    0x6e, 0x7e, 0xdd, 0xfa, 0x8f, 0x83, 0x9b, 0x8a, 0xeb, 0x0b, 0xe2, 0x7d,
+    0xe6, 0xee, 0x8f, 0x40, 0x36, 0x0e, 0x00, 0xac, 0x09, 0x06, 0x99, 0x9b,
+    0x74, 0x11, 0x1e, 0xa4, 0xb6, 0xe7, 0xed, 0xdf, 0xa8, 0xf8, 0x39, 0xb8,
+    0xae, 0xb0, 0xbe, 0x27, 0xde, 0x6e, 0xe8, 0xf4, 0x03, 0x60, 0xe0, 0x0a,
+    0xc0, 0x98,
+};
+static_assert(sizeof(kBytesTestReadSymbol9) == kNumBytesTestReadSymbol9, "");
+
+// The kBytesTestReadSymbol10[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][11] = {
+//   // pmf: 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10
+//   { 32768 - 3277, 32768 - 6554, 32768 - 9830, 32768 - 13107, 32768 - 16384,
+//     32768 - 19661, 32768 - 22938, 32768 - 26214, 32768 - 29491, 0, 0 },
+//   // pmf: 3/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 1/20
+//   { 32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 14746, 32768 - 18022,
+//     32768 - 21299, 32768 - 24576, 32768 - 27853, 32768 - 31130, 0, 0 },
+//   // pmf: 1/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 2/20, 3/20
+//   { 32768 - 1638, 32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 14746,
+//     32768 - 18022, 32768 - 21299, 32768 - 24576, 32768 - 27853, 0, 0 },
+//   // pmf: 1/20, 2/20, 2/20, 2/20, 3/20, 3/20, 2/20, 2/20, 2/20, 1/20
+//   { 32768 - 1638, 32768 - 4915, 32768 - 8192, 32768 - 11469, 32768 - 16384,
+//     32768 - 21299, 32768 - 24576, 32768 - 27853, 32768 - 31130, 0, 0 },
+// };
+// constexpr int kSymbols[20][4] = { { 0, 5, 9, 4 },  //
+//                                   { 1, 6, 8, 3 },  //
+//                                   { 2, 7, 7, 2 },  //
+//                                   { 3, 8, 6, 1 },  //
+//                                   { 4, 9, 5, 0 },  //
+//                                   { 5, 0, 4, 9 },  //
+//                                   { 6, 1, 3, 8 },  //
+//                                   { 7, 2, 2, 7 },  //
+//                                   { 8, 3, 1, 6 },  //
+//                                   { 9, 4, 0, 5 },  //
+//                                   { 0, 0, 9, 7 },  //
+//                                   { 2, 1, 8, 5 },  //
+//                                   { 4, 3, 6, 3 },  //
+//                                   { 6, 5, 4, 1 },  //
+//                                   { 8, 7, 2, 8 },  //
+//                                   { 1, 0, 9, 6 },  //
+//                                   { 3, 2, 7, 4 },  //
+//                                   { 5, 4, 5, 2 },  //
+//                                   { 7, 6, 3, 5 },  //
+//                                   { 9, 8, 1, 4 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 96; ++i) {
+//   for (int j = 0; j < 20; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 10);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol10 = 3204;
+constexpr uint8_t kBytesTestReadSymbol10[] = {
+    0x10, 0x84, 0xe2, 0xe0, 0x0f, 0x08, 0xd6, 0x01, 0xd0, 0xaa, 0xd8, 0xb5,
+    0x60, 0x4f, 0xb9, 0xb3, 0x73, 0x01, 0x8c, 0x92, 0xe6, 0xa0, 0xab, 0xe8,
+    0xe4, 0x95, 0x85, 0x03, 0x5f, 0xbb, 0x3b, 0x1f, 0x27, 0xb1, 0x44, 0x95,
+    0x50, 0x1f, 0xad, 0xc8, 0x35, 0xde, 0x44, 0xf3, 0xb6, 0x8d, 0xa2, 0x39,
+    0xc3, 0xb6, 0xee, 0x3c, 0x10, 0x33, 0x27, 0x7a, 0x29, 0xcc, 0x7c, 0x08,
+    0xcb, 0x94, 0xbe, 0xef, 0x96, 0x47, 0x30, 0x49, 0x47, 0x9c, 0xb7, 0x7e,
+    0x23, 0x0c, 0x27, 0x8e, 0x1b, 0xdc, 0x6c, 0x92, 0x40, 0x98, 0xbf, 0x20,
+    0xd4, 0x01, 0x72, 0x55, 0x8c, 0x3f, 0x3c, 0x76, 0x24, 0xd2, 0x2d, 0xba,
+    0xa4, 0x54, 0x29, 0x80, 0xe9, 0x06, 0x2c, 0x68, 0xbd, 0xa7, 0xc5, 0xf7,
+    0x44, 0xdf, 0x7e, 0x94, 0x90, 0x3f, 0x94, 0x7d, 0x9e, 0x36, 0xb8, 0x82,
+    0x1d, 0x4a, 0x47, 0x1f, 0x6c, 0x29, 0x51, 0xd2, 0x84, 0xa8, 0xcd, 0x98,
+    0xc0, 0xd2, 0xea, 0x4a, 0x25, 0x3c, 0xd7, 0x34, 0x64, 0x96, 0xd4, 0x06,
+    0xed, 0x00, 0x98, 0xc3, 0x65, 0x10, 0xd4, 0xac, 0x6b, 0xab, 0xd7, 0x35,
+    0x04, 0x89, 0xbf, 0x24, 0xcc, 0xfc, 0xc9, 0xe8, 0x87, 0x3d, 0xdb, 0x55,
+    0xf0, 0xc9, 0x97, 0x71, 0x99, 0x00, 0x54, 0x50, 0x24, 0x66, 0xca, 0x24,
+    0xfd, 0x1c, 0xb1, 0x71, 0x0e, 0xb5, 0x9c, 0x27, 0xfc, 0x7f, 0x95, 0x98,
+    0xc8, 0x99, 0x9f, 0x9b, 0xc7, 0xf6, 0x69, 0xfa, 0xb2, 0x11, 0x77, 0x8d,
+    0x02, 0x53, 0x32, 0x4e, 0x20, 0x2c, 0x21, 0x2b, 0x99, 0x9a, 0xec, 0x63,
+    0x0b, 0xe2, 0x8f, 0x30, 0xf8, 0x3c, 0xd1, 0xb1, 0xbc, 0x52, 0x73, 0xce,
+    0x85, 0x54, 0xdd, 0xe6, 0xf6, 0x9c, 0x2d, 0xca, 0x3d, 0xa8, 0x09, 0x34,
+    0xa8, 0x41, 0x9c, 0x03, 0x78, 0xbc, 0x67, 0x11, 0x9f, 0xbe, 0xde, 0x9a,
+    0x98, 0x8a, 0x8d, 0x0b, 0x88, 0x7f, 0xea, 0x82, 0x77, 0x61, 0x7a, 0xde,
+    0xb0, 0xb1, 0x46, 0x8d, 0x23, 0x69, 0x2f, 0x17, 0x05, 0xff, 0x4a, 0x9e,
+    0xf9, 0xb3, 0x9a, 0xd0, 0xc4, 0x81, 0xcf, 0xbc, 0xe6, 0x26, 0x2c, 0x37,
+    0x55, 0xec, 0xdc, 0x23, 0x05, 0xdf, 0x30, 0xcf, 0x5a, 0x4a, 0x0c, 0x08,
+    0xc0, 0xd7, 0x9d, 0x80, 0xc0, 0xa3, 0x56, 0x49, 0x41, 0xc4, 0xdd, 0xc5,
+    0x69, 0x5c, 0xe5, 0x6c, 0xc5, 0xae, 0x4c, 0x95, 0x45, 0xf2, 0xf6, 0xd6,
+    0x12, 0x25, 0xcc, 0x24, 0x56, 0x8c, 0x2b, 0x32, 0x51, 0x18, 0x1a, 0xec,
+    0xb0, 0x62, 0x40, 0x82, 0x59, 0xb8, 0x38, 0x9f, 0x9f, 0x73, 0xf5, 0xb3,
+    0xc3, 0x93, 0xa5, 0x4e, 0xab, 0x7f, 0x97, 0x56, 0x51, 0xb0, 0xff, 0x69,
+    0x73, 0xc2, 0xd0, 0x60, 0x93, 0x59, 0x2f, 0xc7, 0x84, 0x14, 0x7e, 0x68,
+    0xa7, 0x2b, 0x37, 0xb4, 0x2e, 0x69, 0x58, 0x55, 0x3c, 0xd2, 0xf1, 0xa8,
+    0x2b, 0x6e, 0xd5, 0x11, 0x1c, 0x1d, 0x17, 0xd5, 0xf1, 0xfa, 0x8b, 0xd1,
+    0x6c, 0xc2, 0x32, 0x9e, 0x66, 0x3e, 0x6a, 0x4a, 0x0e, 0xb8, 0xf9, 0xa8,
+    0x1c, 0x23, 0xb1, 0x7e, 0xe7, 0xa0, 0x27, 0x5b, 0x1e, 0x8f, 0x8a, 0xb1,
+    0x1e, 0x50, 0x99, 0x9c, 0x39, 0x5b, 0xa0, 0x76, 0xa2, 0x90, 0x20, 0xd5,
+    0x61, 0xf8, 0x96, 0x5a, 0xbc, 0x91, 0x5d, 0xfc, 0x1e, 0xed, 0xea, 0xd8,
+    0x10, 0x5d, 0x15, 0xfa, 0x2b, 0xa7, 0x77, 0xaf, 0xae, 0x64, 0xef, 0x06,
+    0xa4, 0xf7, 0x65, 0x58, 0xb8, 0x64, 0x47, 0xcd, 0xfa, 0x12, 0x8e, 0x7d,
+    0x5b, 0x96, 0x27, 0xda, 0xb9, 0x2a, 0x14, 0xfe, 0x3e, 0x57, 0xd7, 0x4e,
+    0x86, 0xb3, 0x36, 0xd7, 0x77, 0x2d, 0xf6, 0x1e, 0xf3, 0xfd, 0xdb, 0x9a,
+    0x92, 0x78, 0x0a, 0xa4, 0x17, 0xf1, 0x78, 0xfc, 0xc3, 0x6d, 0xa0, 0xf8,
+    0x07, 0x6a, 0x68, 0xb1, 0x1b, 0x00, 0x27, 0x65, 0x68, 0x76, 0x10, 0x39,
+    0x4b, 0x8a, 0x51, 0x7a, 0x53, 0x69, 0x79, 0xfc, 0xbc, 0xe6, 0xf4, 0x26,
+    0xc3, 0xbf, 0x3a, 0x64, 0x56, 0x7d, 0x5f, 0x76, 0xa2, 0x42, 0xd1, 0xad,
+    0x3f, 0xb8, 0xce, 0xfb, 0x79, 0x38, 0xf3, 0x85, 0x2a, 0x67, 0xf4, 0x71,
+    0xfe, 0x0b, 0x79, 0xee, 0x85, 0xe0, 0x61, 0x9c, 0x9d, 0xd5, 0xe0, 0x0a,
+    0xd7, 0xa6, 0x21, 0xc3, 0x60, 0xbf, 0xbd, 0x16, 0xca, 0xa0, 0x16, 0x9d,
+    0xc4, 0x14, 0x99, 0x03, 0x7e, 0xe6, 0x62, 0x6e, 0xbe, 0x18, 0x45, 0x5e,
+    0x15, 0x42, 0xac, 0x5b, 0x60, 0x9f, 0xbd, 0x1e, 0x8a, 0x58, 0x55, 0x75,
+    0xcf, 0xbb, 0x12, 0xcb, 0xc2, 0xf4, 0x01, 0xfc, 0x96, 0x8d, 0x97, 0x67,
+    0x94, 0x65, 0x6b, 0xd0, 0xeb, 0xff, 0x26, 0x30, 0x3a, 0xa0, 0xe9, 0x9b,
+    0xa7, 0x5e, 0x81, 0x2b, 0x8e, 0xf7, 0xd6, 0xbf, 0x6f, 0xe4, 0x33, 0xd5,
+    0xaa, 0x5a, 0x27, 0x18, 0x24, 0x76, 0x72, 0x72, 0x50, 0x72, 0x92, 0x88,
+    0x9f, 0x88, 0x81, 0x0f, 0x33, 0xa7, 0x99, 0x83, 0x53, 0x03, 0x8c, 0x2d,
+    0x36, 0x43, 0x52, 0x27, 0x27, 0x74, 0xcd, 0xf1, 0x1b, 0x76, 0x95, 0x11,
+    0xdf, 0x4e, 0xb3, 0xa5, 0x2e, 0xe4, 0xac, 0x3a, 0xfd, 0x9f, 0xab, 0x96,
+    0x7e, 0xb1, 0xf0, 0x19, 0x22, 0xc4, 0x06, 0x9b, 0xe7, 0xe2, 0xf8, 0xb4,
+    0x17, 0xbd, 0x9d, 0x14, 0xac, 0x11, 0xc9, 0x79, 0x8e, 0x01, 0x23, 0xc9,
+    0x6e, 0x5f, 0x96, 0x1e, 0x99, 0xe1, 0x19, 0x2c, 0xb1, 0x1b, 0x54, 0x30,
+    0x3a, 0xb1, 0xe7, 0xbf, 0xbf, 0x17, 0x3d, 0x9b, 0x86, 0xd7, 0x4b, 0x68,
+    0x46, 0xa6, 0xb0, 0x05, 0x66, 0x4b, 0x8a, 0xdc, 0x60, 0x60, 0x29, 0x95,
+    0x35, 0x4b, 0x6f, 0xf5, 0x73, 0x51, 0x52, 0xb6, 0xec, 0xef, 0x74, 0xcb,
+    0x0b, 0x00, 0x04, 0x15, 0xff, 0xb3, 0x13, 0xdd, 0x70, 0x5e, 0x65, 0xfc,
+    0xa6, 0xb1, 0x13, 0x59, 0x29, 0xd0, 0x2e, 0xc4, 0x55, 0xcb, 0x99, 0xac,
+    0xca, 0x48, 0x67, 0x3e, 0xfb, 0xfb, 0x54, 0xb7, 0x53, 0x32, 0xb4, 0x17,
+    0xf6, 0x78, 0xd1, 0x64, 0x67, 0x76, 0x33, 0x3a, 0xe9, 0x13, 0x8c, 0x9c,
+    0xf1, 0x74, 0xb7, 0xd1, 0x35, 0x41, 0xf2, 0x4d, 0x68, 0x53, 0x25, 0x57,
+    0x97, 0x33, 0x18, 0xea, 0x96, 0xea, 0x66, 0x56, 0x82, 0xfe, 0xcf, 0x1a,
+    0x2c, 0x8c, 0xee, 0xc6, 0x67, 0x5d, 0x22, 0x71, 0x93, 0x9e, 0x2e, 0x96,
+    0xfa, 0x26, 0xa8, 0x3e, 0x49, 0xad, 0x0a, 0x64, 0xaa, 0xf2, 0xe6, 0x63,
+    0x1d, 0x52, 0xfb, 0x67, 0x7e, 0x17, 0x91, 0x70, 0xef, 0x48, 0xe1, 0x2e,
+    0x48, 0xe4, 0x8a, 0xc2, 0x4c, 0x5f, 0x77, 0x7f, 0x03, 0x45, 0xf0, 0x8d,
+    0x44, 0xad, 0x1e, 0xef, 0xb5, 0x1f, 0x3c, 0x3c, 0x4e, 0x43, 0x87, 0xdd,
+    0xec, 0xd9, 0x6e, 0xd0, 0xe8, 0x47, 0x75, 0x5b, 0xe5, 0xc0, 0x76, 0xb1,
+    0x9c, 0x5b, 0x72, 0xeb, 0x15, 0x9c, 0x5a, 0xa1, 0x31, 0xc2, 0x46, 0xb4,
+    0xe7, 0x9b, 0x5d, 0x86, 0x23, 0x3f, 0x47, 0xd9, 0x9b, 0x31, 0x4e, 0xa6,
+    0x65, 0xe9, 0x2f, 0xa3, 0xf8, 0x34, 0x68, 0xf7, 0x61, 0xf5, 0x08, 0xc4,
+    0x8a, 0x10, 0xa1, 0x9b, 0xa9, 0x30, 0x25, 0x8d, 0xaf, 0x67, 0x07, 0x8e,
+    0x84, 0x62, 0xa5, 0xc3, 0x2f, 0x5d, 0x06, 0xaa, 0xd4, 0x02, 0x04, 0x77,
+    0xed, 0xf4, 0xe0, 0xa9, 0xca, 0x95, 0xa2, 0x91, 0xe0, 0x56, 0x64, 0xb6,
+    0xb8, 0x39, 0xda, 0x83, 0xc5, 0x10, 0x7e, 0xa6, 0x08, 0x10, 0x01, 0x15,
+    0x2b, 0x6e, 0xce, 0xfe, 0x43, 0x01, 0xa9, 0xcb, 0xfd, 0xd9, 0x1b, 0x7e,
+    0x11, 0x74, 0x96, 0x4a, 0x89, 0x3f, 0x07, 0xac, 0x74, 0xf9, 0x93, 0xb2,
+    0xf6, 0xed, 0xb3, 0x29, 0xab, 0xc5, 0x0a, 0x90, 0xb3, 0x71, 0x51, 0xa5,
+    0xba, 0x16, 0x01, 0xd4, 0x35, 0x11, 0xdc, 0xba, 0x27, 0xc3, 0x01, 0x05,
+    0x65, 0x91, 0x6b, 0xff, 0x33, 0xb9, 0x9d, 0x84, 0xf7, 0xc0, 0x2d, 0x4b,
+    0xf4, 0xb2, 0x39, 0xe4, 0x7d, 0x0f, 0xf6, 0x8d, 0xa4, 0x2c, 0xa2, 0x4d,
+    0x4e, 0x8a, 0x2e, 0xff, 0x84, 0x5f, 0x43, 0x93, 0xa3, 0x43, 0xa2, 0xe3,
+    0x23, 0x92, 0xf3, 0x57, 0xd2, 0x2e, 0x8e, 0xea, 0xff, 0x2c, 0x3d, 0x1f,
+    0xc6, 0x94, 0x77, 0x19, 0xf6, 0xdb, 0x16, 0x4e, 0xd0, 0x3f, 0x32, 0xf3,
+    0x7b, 0x89, 0x50, 0xc5, 0x5c, 0xfe, 0x86, 0xcf, 0xf6, 0x89, 0x88, 0xa3,
+    0xa8, 0xd9, 0x52, 0x23, 0x68, 0x31, 0x90, 0xe2, 0xd4, 0x3a, 0x62, 0xb4,
+    0xe6, 0x4e, 0xfa, 0x20, 0x21, 0xbf, 0xe5, 0x4e, 0x86, 0x6d, 0xbe, 0xbe,
+    0xc6, 0x25, 0x4b, 0xf2, 0x20, 0x6c, 0x4e, 0xfc, 0x93, 0x41, 0x3f, 0x8b,
+    0x29, 0x34, 0xb9, 0xd1, 0x61, 0xe0, 0x34, 0x83, 0x8e, 0x1f, 0x8c, 0x44,
+    0xe2, 0x95, 0x2e, 0x73, 0x48, 0x8f, 0xeb, 0xd0, 0x6c, 0xec, 0xc4, 0xf6,
+    0x48, 0x5e, 0xf7, 0x53, 0x3e, 0xa6, 0x77, 0x33, 0xb0, 0x9e, 0xf8, 0x05,
+    0xa9, 0x7e, 0x96, 0x47, 0x3c, 0x8f, 0xa1, 0xfe, 0xd1, 0xb4, 0x85, 0x94,
+    0x49, 0xa9, 0xd1, 0x45, 0xdf, 0xf0, 0x8b, 0xe8, 0x72, 0x74, 0x68, 0x74,
+    0x5c, 0x67, 0xc2, 0xbb, 0xcd, 0x7b, 0x6a, 0x2f, 0x6b, 0x0a, 0x1d, 0xec,
+    0x03, 0x48, 0xd2, 0x8e, 0xe3, 0x3e, 0xdb, 0x62, 0xc9, 0xda, 0x07, 0xe6,
+    0x5e, 0x6f, 0x71, 0x2a, 0x18, 0xab, 0x9f, 0xd0, 0xd9, 0xfe, 0xd1, 0xac,
+    0xf0, 0x21, 0xab, 0xd9, 0x70, 0x1e, 0xb9, 0x99, 0xa0, 0xcc, 0xeb, 0xe7,
+    0x87, 0xee, 0xd9, 0x8e, 0xd0, 0xe5, 0xc0, 0x58, 0x75, 0x37, 0x3d, 0x03,
+    0x4e, 0x18, 0x08, 0x27, 0xdd, 0x18, 0x38, 0x1b, 0xad, 0xf1, 0xd3, 0xcc,
+    0xa1, 0x65, 0x26, 0x97, 0x3a, 0x2c, 0x3c, 0x06, 0x90, 0x71, 0xc3, 0xf1,
+    0x88, 0x9c, 0x52, 0xa5, 0xce, 0x69, 0x11, 0xfd, 0x7a, 0x0d, 0x9d, 0x98,
+    0x9e, 0xc9, 0x0b, 0xde, 0xea, 0x67, 0xd4, 0xce, 0xe6, 0x76, 0x13, 0xdf,
+    0x00, 0xb5, 0x2f, 0xd2, 0xc8, 0xe7, 0x91, 0xf4, 0x3f, 0xda, 0x36, 0x90,
+    0xb2, 0x89, 0x35, 0x3a, 0x28, 0xbb, 0xfe, 0x11, 0x7d, 0x0e, 0x4e, 0x8d,
+    0x0e, 0x8b, 0x8c, 0xf8, 0x57, 0x79, 0xaf, 0x6d, 0x45, 0xed, 0x61, 0x43,
+    0xbd, 0x80, 0x69, 0x1a, 0x51, 0xdc, 0x67, 0xdb, 0x6c, 0x59, 0x3b, 0x40,
+    0xfc, 0xcb, 0xcd, 0xee, 0x25, 0x43, 0x15, 0x73, 0xfa, 0x1b, 0x3f, 0xda,
+    0x35, 0x9e, 0x04, 0x35, 0x7b, 0x2e, 0x03, 0xd7, 0x33, 0x34, 0x19, 0x9d,
+    0x7c, 0xf0, 0xfd, 0xdb, 0x31, 0xda, 0x1c, 0xb8, 0x0b, 0x0e, 0xa6, 0xe7,
+    0xa0, 0x69, 0xc3, 0x01, 0x04, 0xfb, 0xa3, 0x07, 0x03, 0x75, 0xbe, 0x3a,
+    0x79, 0x94, 0x2c, 0xa4, 0xd2, 0xe7, 0x45, 0x87, 0x80, 0xd2, 0x0e, 0x38,
+    0x7e, 0x31, 0x13, 0x8a, 0x54, 0xb9, 0xcd, 0x22, 0x3f, 0xaf, 0x41, 0xb3,
+    0xb3, 0x13, 0xd9, 0x21, 0x7b, 0xdd, 0x4c, 0xfa, 0x99, 0xdc, 0xce, 0xc2,
+    0x7b, 0xe0, 0x16, 0xa5, 0xfa, 0x59, 0x1c, 0xf2, 0x3e, 0x87, 0xfb, 0x46,
+    0xd2, 0x16, 0x51, 0x26, 0xa7, 0x45, 0x17, 0x7f, 0xc2, 0x2f, 0xa1, 0xc9,
+    0xd1, 0xa1, 0xd1, 0x71, 0x9f, 0x0a, 0xef, 0x35, 0xed, 0xa8, 0xbd, 0xac,
+    0x28, 0x77, 0xb0, 0x0d, 0x23, 0x4a, 0x3b, 0x8c, 0xfb, 0x6d, 0x8b, 0x27,
+    0x68, 0x1f, 0x99, 0x79, 0xbd, 0xc4, 0xa8, 0x62, 0xae, 0x7f, 0x43, 0x67,
+    0xfb, 0x46, 0xb3, 0xc0, 0x86, 0xaf, 0x65, 0xc0, 0x7a, 0xe6, 0x66, 0x83,
+    0x33, 0xaf, 0x9e, 0x1f, 0xbb, 0x66, 0x3b, 0x43, 0x97, 0x01, 0x61, 0xd4,
+    0xdc, 0xf4, 0x0d, 0x38, 0x60, 0x20, 0x9f, 0x74, 0x60, 0xe0, 0x6e, 0xb7,
+    0xc7, 0x4f, 0x32, 0x85, 0x94, 0x9a, 0x5c, 0xe8, 0xb0, 0xf0, 0x1a, 0x41,
+    0xc7, 0x0f, 0xc6, 0x22, 0x71, 0x4a, 0x97, 0x39, 0xa4, 0x47, 0xf5, 0xe8,
+    0x36, 0x76, 0x62, 0x7b, 0x24, 0x2f, 0x7b, 0xa9, 0x9f, 0x53, 0x3b, 0x99,
+    0xd8, 0x4f, 0x7c, 0x02, 0xd4, 0xbf, 0x4b, 0x23, 0x9e, 0x47, 0xd0, 0xff,
+    0x68, 0xda, 0x42, 0xca, 0x24, 0xd4, 0xe8, 0xa2, 0xef, 0xf8, 0x45, 0xf4,
+    0x39, 0x3a, 0x34, 0x3a, 0x2e, 0x33, 0xe1, 0x5d, 0xe6, 0xbd, 0xb5, 0x17,
+    0xb5, 0x85, 0x0e, 0xf6, 0x01, 0xa4, 0x69, 0x47, 0x71, 0x9f, 0x6d, 0xb1,
+    0x64, 0xed, 0x03, 0xf3, 0x2f, 0x37, 0xb8, 0x95, 0x0c, 0x55, 0xcf, 0xe8,
+    0x6c, 0xff, 0x68, 0xd6, 0x78, 0x10, 0xd5, 0xec, 0xb8, 0x0f, 0x5c, 0xcc,
+    0xd0, 0x66, 0x75, 0xf3, 0xc3, 0xf7, 0x6c, 0xc7, 0x68, 0x72, 0xe0, 0x2c,
+    0x3a, 0x9b, 0x9e, 0x81, 0xa7, 0x0c, 0x04, 0x13, 0xee, 0x8c, 0x1c, 0x0d,
+    0xd6, 0xf8, 0xe9, 0xe6, 0x50, 0xb2, 0x93, 0x4b, 0x9d, 0x16, 0x1e, 0x03,
+    0x48, 0x38, 0xe1, 0xf8, 0xc4, 0x4e, 0x29, 0x52, 0xe7, 0x34, 0x88, 0xfe,
+    0xbd, 0x06, 0xce, 0xcc, 0x4f, 0x64, 0x85, 0xef, 0x75, 0x33, 0xea, 0x67,
+    0x73, 0x3b, 0x09, 0xef, 0x80, 0x5a, 0x97, 0xe9, 0x64, 0x73, 0xc8, 0xfa,
+    0x1f, 0xed, 0x1b, 0x48, 0x59, 0x44, 0x9a, 0x9d, 0x14, 0x5d, 0xff, 0x08,
+    0xbe, 0x87, 0x27, 0x46, 0x87, 0x45, 0xc6, 0x7c, 0x2b, 0xbc, 0xd7, 0xb6,
+    0xa2, 0xf6, 0xb0, 0xa1, 0xde, 0xc0, 0x34, 0x8d, 0x28, 0xee, 0x33, 0xed,
+    0xb6, 0x2c, 0x9d, 0xa0, 0x7e, 0x65, 0xe6, 0xf7, 0x12, 0xa1, 0x8a, 0xb9,
+    0xfd, 0x0d, 0x9f, 0xed, 0x1a, 0xcf, 0x02, 0x1a, 0xbd, 0x97, 0x01, 0xeb,
+    0x99, 0x9a, 0x0c, 0xce, 0xbe, 0x78, 0x7e, 0xed, 0x98, 0xed, 0x0e, 0x5c,
+    0x05, 0x87, 0x53, 0x73, 0xd0, 0x34, 0xe1, 0x80, 0x82, 0x7d, 0xd1, 0x83,
+    0x81, 0xba, 0xdf, 0x1d, 0x3c, 0xca, 0x16, 0x52, 0x69, 0x73, 0xa2, 0xc3,
+    0xc0, 0x69, 0x07, 0x1c, 0x3f, 0x18, 0x89, 0xc5, 0x2a, 0x5c, 0xe6, 0x91,
+    0x1f, 0xd7, 0xa0, 0xd9, 0xd9, 0x89, 0xec, 0x90, 0xbd, 0xee, 0xa6, 0x7d,
+    0x4c, 0xee, 0x67, 0x61, 0x3d, 0xf0, 0x0b, 0x52, 0xfd, 0x2c, 0x8e, 0x79,
+    0x1f, 0x43, 0xfd, 0xa3, 0x69, 0x0b, 0x28, 0x93, 0x53, 0xa2, 0x8b, 0xbf,
+    0xe1, 0x17, 0xd0, 0xe4, 0xe8, 0xd0, 0xe8, 0xb8, 0xcf, 0x85, 0x77, 0x9a,
+    0xf6, 0xd4, 0x5e, 0xd6, 0x14, 0x3b, 0xd8, 0x06, 0x91, 0xa5, 0x1d, 0xc6,
+    0x7d, 0xb6, 0xc5, 0x93, 0xb4, 0x0f, 0xcc, 0xbc, 0xde, 0xe2, 0x54, 0x31,
+    0x57, 0x3f, 0xa1, 0xb3, 0xfd, 0xa3, 0x59, 0xe0, 0x43, 0x57, 0xb2, 0xe0,
+    0x3d, 0x73, 0x33, 0x41, 0x99, 0xd7, 0xcf, 0x0f, 0xdd, 0xb3, 0x1d, 0xa1,
+    0xcb, 0x80, 0xb0, 0xea, 0x6e, 0x7a, 0x06, 0x9c, 0x30, 0x10, 0x4f, 0xba,
+    0x30, 0x70, 0x37, 0x5b, 0xe3, 0xa7, 0x99, 0x42, 0xca, 0x4d, 0x2e, 0x74,
+    0x58, 0x78, 0x0d, 0x20, 0xe3, 0x87, 0xe3, 0x11, 0x38, 0xa5, 0x4b, 0x9c,
+    0xd2, 0x23, 0xfa, 0xf4, 0x1b, 0x3b, 0x31, 0x3d, 0x92, 0x17, 0xbd, 0xd4,
+    0xcf, 0xa9, 0x9d, 0xcc, 0xec, 0x27, 0xbe, 0x01, 0x6a, 0x5f, 0xa5, 0x91,
+    0xcf, 0x23, 0xe8, 0x7f, 0xb4, 0x6d, 0x21, 0x65, 0x12, 0x6a, 0x74, 0x51,
+    0x77, 0xfc, 0x22, 0xfa, 0x1c, 0x9d, 0x1a, 0x1d, 0x17, 0x19, 0xf0, 0xae,
+    0xf3, 0x5e, 0xda, 0x8b, 0xda, 0xc2, 0x87, 0x7b, 0x00, 0xd2, 0x34, 0xa3,
+    0xb8, 0xcf, 0xb6, 0xd8, 0xb2, 0x76, 0x81, 0xf9, 0x97, 0x9b, 0xdc, 0x4a,
+    0x86, 0x2a, 0xe7, 0xf4, 0x36, 0x7f, 0xb4, 0x6b, 0x3c, 0x08, 0x6a, 0xf6,
+    0x5c, 0x07, 0xae, 0x66, 0x68, 0x33, 0x3a, 0xf9, 0xe1, 0xfb, 0xb6, 0x63,
+    0xb4, 0x39, 0x70, 0x16, 0x1d, 0x4d, 0xcf, 0x40, 0xd3, 0x86, 0x02, 0x09,
+    0xf7, 0x46, 0x0e, 0x06, 0xda, 0x64, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5,
+    0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9,
+    0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7,
+    0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54,
+    0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66,
+    0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75,
+    0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca,
+    0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49,
+    0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09,
+    0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc,
+    0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66,
+    0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8,
+    0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e,
+    0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b,
+    0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b,
+    0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20,
+    0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8,
+    0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01,
+    0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f,
+    0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed,
+    0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0,
+    0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e,
+    0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65,
+    0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe,
+    0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36,
+    0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5,
+    0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9,
+    0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7,
+    0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54,
+    0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66,
+    0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75,
+    0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca,
+    0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49,
+    0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09,
+    0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc,
+    0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66,
+    0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8,
+    0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e,
+    0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b,
+    0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b,
+    0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20,
+    0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8,
+    0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01,
+    0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f,
+    0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed,
+    0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0,
+    0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e,
+    0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65,
+    0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe,
+    0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36,
+    0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5,
+    0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9,
+    0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7,
+    0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54,
+    0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66,
+    0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75,
+    0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca,
+    0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49,
+    0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09,
+    0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc,
+    0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66,
+    0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8,
+    0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e,
+    0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b,
+    0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b,
+    0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20,
+    0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8,
+    0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01,
+    0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f,
+    0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed,
+    0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0,
+    0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e,
+    0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65,
+    0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe,
+    0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36,
+    0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5,
+    0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9,
+    0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7,
+    0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8, 0xed, 0xfd, 0x74, 0x54,
+    0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e, 0x1f, 0x77, 0xb3, 0x66,
+    0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b, 0xb4, 0xe3, 0x30, 0x75,
+    0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b, 0x83, 0x5c, 0xcd, 0xca,
+    0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20, 0x88, 0x54, 0xe4, 0x49,
+    0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8, 0x9d, 0xe4, 0x9a, 0x09,
+    0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01, 0xa4, 0x1c, 0x70, 0xfc,
+    0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f, 0x5e, 0x83, 0x67, 0x66,
+    0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1c, 0xed, 0x58, 0x51, 0xe8, 0xc8,
+    0xed, 0xfd, 0x74, 0x54, 0x95, 0x92, 0xa1, 0xa0, 0xf0, 0xf1, 0x39, 0x0e,
+    0x1f, 0x77, 0xb3, 0x66, 0xb2, 0x83, 0x37, 0x4e, 0x1a, 0xd0, 0x2f, 0x9b,
+    0xb4, 0xe3, 0x30, 0x75, 0xf5, 0x52, 0x42, 0x65, 0xe3, 0x9e, 0x7d, 0x6b,
+    0x83, 0x5c, 0xcd, 0xca, 0xad, 0x28, 0x53, 0xbe, 0xb6, 0xad, 0x46, 0x20,
+    0x88, 0x54, 0xe4, 0x49, 0x1d, 0xee, 0xcb, 0x36, 0x69, 0x66, 0x09, 0xa8,
+    0x9d, 0xe4, 0x9a, 0x09, 0xfc, 0x59, 0x49, 0xa5, 0xce, 0x8b, 0x0f, 0x01,
+    0xa4, 0x1c, 0x70, 0xfc, 0x62, 0x27, 0x14, 0xa9, 0x73, 0x9a, 0x44, 0x7f,
+    0x5e, 0x83, 0x67, 0x66, 0x27, 0xb2, 0x42, 0xf7, 0xba, 0x97, 0x1d, 0x80,
+};
+static_assert(sizeof(kBytesTestReadSymbol10) == kNumBytesTestReadSymbol10, "");
+
+// The kBytesTestReadSymbol11[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][12] = {
+//   // pmf: 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11, 1/11
+//   { 32768 - 2979, 32768 - 5958, 32768 - 8937, 32768 - 11916, 32768 - 14895,
+//     32768 - 17873, 32768 - 20852, 32768 - 23831, 32768 - 26810,
+//     32768 - 29789, 0, 0 },
+//   // pmf: 3/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 1/22
+//   { 32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405, 32768 - 16384,
+//     32768 - 19363, 32768 - 22342, 32768 - 25321, 32768 - 28300,
+//     32768 - 31279, 0, 0 },
+//   // pmf: 1/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 2/22, 3/22
+//   { 32768 - 1489, 32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405,
+//     32768 - 16384, 32768 - 19363, 32768 - 22342, 32768 - 25321,
+//     32768 - 28300, 0, 0 },
+//   // pmf: 1/22, 2/22, 2/22, 2/22, 2/22, 4/22, 2/22, 2/22, 2/22, 2/22, 1/22
+//   { 32768 - 1489, 32768 - 4468, 32768 - 7447, 32768 - 10426, 32768 - 13405,
+//     32768 - 19363, 32768 - 22342, 32768 - 25321, 32768 - 28300,
+//     32768 - 31279, 0, 0 },
+// };
+// constexpr int kSymbols[22][4] = { { 0, 6, 10, 5 },   //
+//                                   { 1, 7, 9, 4 },    //
+//                                   { 2, 8, 8, 3 },    //
+//                                   { 3, 9, 7, 2 },    //
+//                                   { 4, 10, 6, 1 },   //
+//                                   { 5, 0, 5, 0 },    //
+//                                   { 6, 1, 4, 10 },   //
+//                                   { 7, 2, 3, 9 },    //
+//                                   { 8, 3, 2, 8 },    //
+//                                   { 9, 4, 1, 7 },    //
+//                                   { 10, 5, 0, 6 },   //
+//                                   { 0, 0, 10, 9 },   //
+//                                   { 2, 1, 8, 7 },    //
+//                                   { 4, 3, 6, 5 },    //
+//                                   { 6, 5, 4, 3 },    //
+//                                   { 8, 7, 2, 1 },    //
+//                                   { 10, 9, 10, 8 },  //
+//                                   { 1, 0, 9, 6 },    //
+//                                   { 3, 2, 7, 4 },    //
+//                                   { 5, 4, 5, 2 },    //
+//                                   { 7, 6, 3, 5 },    //
+//                                   { 9, 8, 1, 5 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 96; ++i) {
+//   for (int j = 0; j < 22; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 11);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol11 = 3673;
+constexpr uint8_t kBytesTestReadSymbol11[] = {
+    0x0f, 0xb4, 0x93, 0xdb, 0xbe, 0x10, 0xa5, 0x0b, 0xa6, 0x53, 0x86, 0x25,
+    0xaf, 0x5e, 0xf9, 0xd6, 0x10, 0xd8, 0x5e, 0x2b, 0x6d, 0xf2, 0xf8, 0x35,
+    0x97, 0xf6, 0x95, 0xeb, 0x67, 0x20, 0x49, 0x0e, 0x21, 0xb4, 0x73, 0x5e,
+    0x72, 0x06, 0xdd, 0x76, 0x99, 0x3d, 0x67, 0x37, 0x27, 0xea, 0x21, 0x80,
+    0xc6, 0xb8, 0xf7, 0x48, 0x5e, 0x11, 0xe2, 0xe7, 0x10, 0xad, 0x0b, 0x12,
+    0x52, 0xd4, 0xe3, 0x63, 0x2a, 0x1d, 0x41, 0xf4, 0xce, 0x5d, 0x58, 0x5f,
+    0x79, 0x6d, 0xdd, 0x4b, 0x3d, 0x99, 0xd9, 0x64, 0xdc, 0x08, 0x16, 0x1a,
+    0xf3, 0x8f, 0x1e, 0x33, 0xfe, 0x7a, 0x49, 0xaa, 0x98, 0xb9, 0xe2, 0xc6,
+    0x14, 0xb8, 0x51, 0x1f, 0x45, 0xce, 0xea, 0x97, 0xcd, 0xd0, 0x0b, 0x5d,
+    0x12, 0x31, 0xbe, 0x78, 0x98, 0xa3, 0x77, 0x6a, 0xa0, 0xef, 0x57, 0x3a,
+    0xc6, 0xe7, 0x52, 0x22, 0x06, 0x44, 0x35, 0x8e, 0xc9, 0xe8, 0x4f, 0x76,
+    0xd9, 0x77, 0x8c, 0x80, 0xc9, 0xfc, 0x20, 0x0d, 0xc0, 0x67, 0x95, 0x21,
+    0x93, 0x74, 0x4f, 0xf1, 0xf5, 0xdf, 0x5a, 0x10, 0xde, 0x57, 0xc8, 0x6e,
+    0x33, 0x40, 0xae, 0x36, 0x4a, 0xc8, 0x49, 0xbf, 0x0d, 0x6d, 0x74, 0x34,
+    0xff, 0xdc, 0x1b, 0xe3, 0xcf, 0xcf, 0xe6, 0xd1, 0xfb, 0x4d, 0xd5, 0x0e,
+    0x86, 0x83, 0x21, 0x12, 0xf8, 0x51, 0x2a, 0xc4, 0x87, 0xd8, 0x1b, 0x1d,
+    0xe7, 0x36, 0xb5, 0xc3, 0xf9, 0xf9, 0x8f, 0x0f, 0xc2, 0x21, 0x83, 0x75,
+    0x14, 0x81, 0x17, 0xb1, 0x9b, 0x51, 0x56, 0x1d, 0xa1, 0xaa, 0xff, 0xd4,
+    0x1f, 0xf3, 0x8d, 0xd1, 0x30, 0x53, 0x92, 0x69, 0xce, 0xf0, 0xc5, 0x75,
+    0xcf, 0xd2, 0x6e, 0x37, 0x74, 0x79, 0xc3, 0x50, 0x52, 0x01, 0xc4, 0x0f,
+    0x67, 0xe2, 0xb7, 0xe2, 0xf1, 0xcc, 0xd9, 0x49, 0xc4, 0x58, 0xbd, 0x8d,
+    0x91, 0xb8, 0x35, 0xbd, 0x64, 0x12, 0x24, 0x20, 0x20, 0x29, 0x23, 0x94,
+    0x85, 0xb6, 0xa8, 0x4e, 0xd4, 0x49, 0x09, 0x25, 0xc4, 0xc5, 0xa5, 0x0c,
+    0x76, 0xa9, 0x4a, 0x75, 0x0f, 0xb9, 0x57, 0x33, 0xcd, 0xfd, 0xf8, 0x8f,
+    0xae, 0x43, 0x48, 0xb8, 0xea, 0x87, 0x17, 0x0d, 0x3d, 0x8b, 0x9a, 0x21,
+    0xe8, 0xbf, 0xc8, 0x5e, 0x18, 0x48, 0xa3, 0xcd, 0x08, 0x59, 0x9b, 0xdb,
+    0x79, 0x5c, 0xe9, 0xa3, 0xe6, 0xba, 0x58, 0x53, 0x10, 0x9a, 0x2c, 0x2b,
+    0x10, 0x5b, 0x96, 0x9a, 0x1f, 0x8f, 0xc2, 0x7d, 0xee, 0xe9, 0xc2, 0xbc,
+    0x8f, 0x8b, 0xa7, 0x41, 0xb1, 0x33, 0x58, 0x6e, 0x25, 0x13, 0x3a, 0xd0,
+    0x78, 0x53, 0xda, 0xa2, 0x35, 0x23, 0x89, 0x39, 0xa7, 0xef, 0x94, 0xda,
+    0x2f, 0xc3, 0x17, 0x80, 0x27, 0xc7, 0x0f, 0xda, 0xfb, 0xda, 0x64, 0x3c,
+    0x94, 0x8c, 0x39, 0xd0, 0x06, 0x62, 0x6c, 0x0d, 0x26, 0xba, 0x4f, 0xcb,
+    0x8a, 0xa0, 0xbc, 0xeb, 0x3f, 0x65, 0x51, 0x8e, 0x1d, 0x2e, 0x9e, 0x5f,
+    0xe3, 0x15, 0x0e, 0x58, 0x4f, 0xb7, 0xb6, 0x64, 0x95, 0xe8, 0x0e, 0x00,
+    0x7c, 0x1e, 0xd9, 0xde, 0x35, 0x5a, 0xff, 0xd5, 0xe5, 0xb3, 0x64, 0xcc,
+    0x8b, 0x93, 0xbc, 0x2a, 0x25, 0x7d, 0x50, 0x92, 0x3e, 0x23, 0x4c, 0x07,
+    0x5e, 0xcf, 0xbb, 0x52, 0xd0, 0xc4, 0xd9, 0x77, 0x66, 0x01, 0x57, 0x1f,
+    0xa0, 0x9d, 0xb2, 0x6d, 0x4e, 0x36, 0xc1, 0x9a, 0x70, 0x4e, 0xa3, 0x5f,
+    0xf6, 0xf9, 0x50, 0x08, 0xcd, 0xf9, 0xe5, 0x76, 0x81, 0xea, 0x88, 0x2e,
+    0xf5, 0x2a, 0xd4, 0x31, 0x39, 0x8d, 0xfe, 0x1c, 0x15, 0x1d, 0x41, 0x2b,
+    0x55, 0xc7, 0xe8, 0x27, 0x6f, 0xc3, 0xf0, 0x23, 0x76, 0x9a, 0xb2, 0x87,
+    0x0c, 0x71, 0x3c, 0x73, 0xea, 0x20, 0x93, 0xf4, 0x21, 0x56, 0xfb, 0x8e,
+    0xd7, 0xaf, 0xc3, 0xd4, 0xf4, 0x31, 0x6f, 0xe8, 0x1f, 0x5b, 0x83, 0xa9,
+    0x2b, 0x83, 0x08, 0x2e, 0xa2, 0xf3, 0x6c, 0x06, 0xe5, 0x89, 0x73, 0x73,
+    0x98, 0x0e, 0x57, 0x07, 0x49, 0x68, 0xa4, 0xb2, 0x4a, 0x26, 0xd1, 0x91,
+    0x49, 0x87, 0x05, 0x55, 0xa4, 0x88, 0x7d, 0x3d, 0x57, 0x7c, 0x20, 0x8c,
+    0x2c, 0xea, 0x30, 0x63, 0x3a, 0xe4, 0xab, 0x27, 0x80, 0xab, 0xfb, 0x22,
+    0x8a, 0x0f, 0xe0, 0xe9, 0xc5, 0xd5, 0x4f, 0x8a, 0x2c, 0x28, 0x36, 0x63,
+    0xbd, 0xa3, 0xc4, 0x90, 0xe4, 0x9e, 0x98, 0xca, 0xce, 0xfc, 0x96, 0xb8,
+    0x22, 0x0d, 0x17, 0xc8, 0xad, 0xc7, 0x01, 0x38, 0x6e, 0x95, 0x30, 0x74,
+    0xda, 0xb8, 0xa9, 0xa8, 0xe6, 0xf2, 0x03, 0x41, 0xb2, 0x05, 0x37, 0x04,
+    0x8b, 0x51, 0xf9, 0xeb, 0x97, 0xdf, 0xe9, 0xa8, 0x5f, 0x11, 0x2f, 0x9f,
+    0x4f, 0xbe, 0xc1, 0x53, 0x2c, 0x75, 0x90, 0xca, 0xa3, 0x9b, 0xc1, 0x36,
+    0xa3, 0x03, 0x65, 0xab, 0x57, 0xc4, 0x0e, 0x8a, 0x41, 0xfc, 0x60, 0x65,
+    0x13, 0x87, 0x6d, 0xda, 0x00, 0xad, 0x56, 0x1c, 0x28, 0x7c, 0x4c, 0xa2,
+    0x92, 0xda, 0x23, 0x00, 0xe8, 0x60, 0x20, 0x59, 0x45, 0x4a, 0x26, 0xae,
+    0x22, 0x37, 0x7c, 0x14, 0xce, 0xff, 0x0d, 0xa9, 0xef, 0xfc, 0x93, 0xbd,
+    0xde, 0x2b, 0x0f, 0xc7, 0xc0, 0x8a, 0x90, 0x06, 0xec, 0x53, 0x9f, 0xc8,
+    0x5b, 0x7b, 0xe8, 0x38, 0x22, 0x75, 0xe9, 0x40, 0xbc, 0x62, 0xe9, 0x9d,
+    0x49, 0xab, 0x88, 0x8d, 0xdf, 0x05, 0x33, 0xbf, 0xc3, 0x69, 0x6c, 0x36,
+    0x71, 0x17, 0x70, 0xc1, 0xe0, 0xd1, 0x71, 0xcf, 0xd5, 0x48, 0x83, 0x50,
+    0x74, 0x07, 0xc4, 0xca, 0x29, 0x2d, 0xa2, 0x30, 0x0e, 0x86, 0x02, 0x05,
+    0x94, 0x54, 0xa2, 0x6a, 0xe2, 0x23, 0x77, 0xc1, 0x4c, 0xef, 0xa4, 0x8c,
+    0xbe, 0x6b, 0x0f, 0x7c, 0x05, 0x30, 0x78, 0x34, 0x5c, 0x73, 0xf5, 0x52,
+    0x20, 0xd4, 0x1d, 0x01, 0xca, 0x9f, 0x89, 0x3b, 0x91, 0x1d, 0x1f, 0x27,
+    0xe1, 0xf9, 0xe8, 0xd0, 0xb2, 0x56, 0x32, 0x15, 0x37, 0xa3, 0x08, 0x38,
+    0xb7, 0x57, 0xb4, 0x09, 0xfe, 0xf4, 0x72, 0xe1, 0x8f, 0x4b, 0x6b, 0x00,
+    0x8c, 0xc5, 0x39, 0xd5, 0x45, 0x45, 0xbb, 0xf6, 0xb7, 0x01, 0xde, 0xef,
+    0x8b, 0xaf, 0x85, 0x73, 0xc4, 0x93, 0x3f, 0xbe, 0xf8, 0x69, 0xbd, 0x71,
+    0xa9, 0x65, 0x6f, 0x22, 0xa6, 0xca, 0x36, 0xf0, 0x34, 0x1b, 0x20, 0x24,
+    0x6c, 0xd2, 0xe3, 0xbb, 0xb5, 0x80, 0xfc, 0xc4, 0x90, 0x54, 0x70, 0xab,
+    0xb7, 0xb9, 0xdb, 0xeb, 0x3b, 0x1d, 0x75, 0xc8, 0x82, 0x9a, 0x15, 0x8a,
+    0x88, 0xb0, 0x7a, 0x77, 0xcf, 0xdc, 0x96, 0x22, 0x4d, 0x08, 0x47, 0x9a,
+    0x06, 0x3e, 0x47, 0xb1, 0x54, 0xdf, 0x22, 0x9d, 0x75, 0x8f, 0xdb, 0xc4,
+    0x5a, 0xd0, 0xfe, 0x44, 0xc4, 0xce, 0x9a, 0x57, 0x0b, 0x20, 0x36, 0x07,
+    0xb1, 0xcf, 0xfe, 0xb4, 0x3e, 0x03, 0x1b, 0x5d, 0xac, 0x40, 0x54, 0x88,
+    0x52, 0x2e, 0x81, 0x8f, 0x3c, 0x52, 0x87, 0x68, 0x00, 0xa5, 0x95, 0xbc,
+    0xd9, 0x67, 0x87, 0xa0, 0x75, 0x78, 0xb6, 0xa9, 0xda, 0x76, 0x9d, 0xe4,
+    0x5a, 0x6d, 0xd5, 0x78, 0xcd, 0x7b, 0x26, 0x5f, 0xc0, 0x09, 0xab, 0x25,
+    0x16, 0x38, 0xa1, 0x86, 0xa7, 0x5e, 0x5e, 0x2d, 0x3e, 0x2f, 0x09, 0xdc,
+    0x31, 0x4d, 0x71, 0x2e, 0xec, 0x5f, 0xa0, 0xe0, 0x8f, 0x9c, 0xcd, 0x72,
+    0xc8, 0x05, 0xa3, 0xb0, 0xfc, 0x4c, 0xdb, 0x6b, 0x24, 0xf2, 0x92, 0x6b,
+    0x13, 0x79, 0x1c, 0x36, 0x90, 0x20, 0x71, 0xaa, 0x8c, 0x1c, 0xe4, 0xbf,
+    0x54, 0xf8, 0x48, 0x51, 0xd2, 0x9a, 0x23, 0xa0, 0x55, 0x38, 0x24, 0x17,
+    0x39, 0x89, 0x4f, 0xc9, 0x01, 0x77, 0x05, 0x16, 0x97, 0x3e, 0xac, 0x9f,
+    0xba, 0x4a, 0xb1, 0x7e, 0x47, 0x0d, 0xa4, 0x08, 0x1c, 0x6a, 0xa3, 0x07,
+    0x39, 0x2f, 0xd5, 0x3e, 0x12, 0x14, 0x74, 0xa6, 0x88, 0xe8, 0x15, 0x4e,
+    0x09, 0x05, 0xce, 0x62, 0x53, 0xf2, 0x40, 0x7b, 0x49, 0x58, 0xc8, 0x5d,
+    0x29, 0x54, 0xb1, 0xfd, 0xb0, 0xb2, 0x75, 0x2c, 0x55, 0x9f, 0xf9, 0x57,
+    0x58, 0xec, 0xfb, 0xff, 0xa3, 0xa0, 0x27, 0x02, 0x0e, 0xa7, 0x52, 0xe7,
+    0x9e, 0xbd, 0xb6, 0x1d, 0xe6, 0x7e, 0xa2, 0xc0, 0x95, 0xe1, 0x4d, 0xd5,
+    0x78, 0xce, 0x08, 0x2d, 0xff, 0x0b, 0xe8, 0x34, 0xa7, 0x53, 0x15, 0x67,
+    0xfe, 0x55, 0xd6, 0x3b, 0x3e, 0xff, 0xe8, 0xe8, 0x09, 0xc0, 0x83, 0xa9,
+    0xd4, 0xb9, 0xe7, 0xaf, 0x6d, 0x87, 0x79, 0x9f, 0xa8, 0xb0, 0x25, 0x78,
+    0x92, 0x0e, 0x9d, 0xf7, 0x55, 0xd9, 0x1a, 0xc5, 0x48, 0x6c, 0xbe, 0x66,
+    0xb0, 0xf7, 0xbf, 0x95, 0x75, 0x8e, 0xcf, 0xbf, 0xfa, 0x3a, 0x02, 0x70,
+    0x20, 0xde, 0xb0, 0xe4, 0xe4, 0x0e, 0x59, 0x44, 0x11, 0x28, 0xe1, 0x22,
+    0xe8, 0x0e, 0x5b, 0x62, 0x69, 0x46, 0xb2, 0x1a, 0x9b, 0x63, 0x75, 0x31,
+    0xb9, 0x4a, 0x90, 0x8d, 0x2e, 0xf8, 0xa8, 0xdb, 0x5a, 0x31, 0xcf, 0x9c,
+    0x99, 0xd5, 0x85, 0x99, 0x5e, 0x0a, 0x51, 0x8d, 0x0d, 0x77, 0x3c, 0x51,
+    0xe1, 0x98, 0x1c, 0x5a, 0xc1, 0xea, 0x38, 0x93, 0x44, 0xd7, 0xb6, 0xbb,
+    0xa1, 0x0f, 0x38, 0x75, 0x5e, 0xff, 0x2d, 0x93, 0xfa, 0x7d, 0xca, 0xf6,
+    0xb7, 0x4f, 0x5e, 0xbd, 0x3f, 0xbc, 0xb6, 0xc6, 0x7b, 0xae, 0x23, 0x97,
+    0xc7, 0xcb, 0xa7, 0x98, 0x37, 0xf4, 0xd6, 0x0c, 0x12, 0xd6, 0xad, 0xc7,
+    0x51, 0xb3, 0x0e, 0x88, 0x40, 0xfd, 0xf7, 0x1b, 0x29, 0xcf, 0xb8, 0x7c,
+    0x29, 0xa1, 0xa2, 0x72, 0x05, 0xa1, 0x0f, 0x43, 0xa8, 0xc4, 0x24, 0x49,
+    0x96, 0xbf, 0x56, 0xe4, 0xbf, 0xc7, 0x71, 0x5a, 0x18, 0x85, 0x65, 0xdd,
+    0x17, 0x95, 0x30, 0x18, 0x8b, 0x18, 0xd2, 0xb2, 0x3f, 0x2e, 0xe9, 0x69,
+    0x89, 0x90, 0xe0, 0x24, 0x08, 0x13, 0x23, 0x0a, 0x78, 0x59, 0x1e, 0xe6,
+    0x33, 0x0f, 0x12, 0x73, 0xba, 0xb3, 0x3c, 0x1d, 0x05, 0x71, 0x7a, 0xd7,
+    0x87, 0xd3, 0xaa, 0x7c, 0xb9, 0x3f, 0x74, 0x95, 0x62, 0xfc, 0x85, 0xac,
+    0xe0, 0xe9, 0xaa, 0x6f, 0x48, 0x4b, 0xdf, 0xb6, 0x9a, 0x7c, 0x24, 0x28,
+    0xe3, 0x6e, 0x40, 0xbd, 0x03, 0xab, 0xc5, 0xb5, 0x4e, 0xd3, 0xb4, 0xef,
+    0x23, 0x1e, 0x6e, 0xab, 0xc6, 0x70, 0x41, 0x6f, 0xf8, 0x5f, 0x41, 0xa5,
+    0x3a, 0x98, 0xab, 0x3f, 0xf2, 0xae, 0xb1, 0xd9, 0xf7, 0xff, 0xf0, 0x29,
+    0xdf, 0x01, 0xed, 0xe9, 0xa3, 0x49, 0xc6, 0x1a, 0xec, 0xa3, 0x4e, 0x59,
+    0x4b, 0xcd, 0x01, 0xcb, 0x6c, 0x4d, 0x28, 0xd6, 0x43, 0x53, 0x6c, 0x6e,
+    0xa6, 0x37, 0x29, 0x52, 0x11, 0xa5, 0xdf, 0x15, 0x1b, 0x6b, 0x46, 0x3a,
+    0x25, 0x93, 0x5c, 0x76, 0xdc, 0x12, 0xb8, 0x3e, 0xe0, 0xc4, 0xb8, 0xf8,
+    0x96, 0x8e, 0xde, 0x49, 0xff, 0x58, 0x3d, 0x47, 0x12, 0x68, 0x9a, 0xf6,
+    0xd7, 0x74, 0x21, 0xe7, 0x0e, 0xab, 0xdf, 0xe5, 0xb2, 0x7f, 0x4f, 0xb9,
+    0x5e, 0xd6, 0xf7, 0x7a, 0xc8, 0x7e, 0xd7, 0xc0, 0x81, 0x63, 0xff, 0x84,
+    0x30, 0x67, 0x40, 0x95, 0xcb, 0x03, 0x6b, 0xfb, 0x08, 0xd3, 0x09, 0xa8,
+    0x93, 0x11, 0xf7, 0xf3, 0x68, 0x89, 0x79, 0x0d, 0x74, 0xce, 0xe9, 0xc6,
+    0x83, 0xcd, 0xe0, 0x54, 0x51, 0xff, 0xe2, 0x3d, 0x76, 0x94, 0x72, 0xed,
+    0xb3, 0x66, 0x98, 0x97, 0xd9, 0x0b, 0x3b, 0x1d, 0x75, 0xc8, 0xfd, 0x9a,
+    0x15, 0x8a, 0x7c, 0xe9, 0xb6, 0x8e, 0x59, 0xf1, 0xbe, 0x8f, 0xe4, 0x3d,
+    0xdd, 0x72, 0x98, 0x71, 0xe5, 0xef, 0xdc, 0x86, 0x2f, 0x9d, 0x75, 0x8c,
+    0xe9, 0xbf, 0xd1, 0x89, 0xae, 0x44, 0xda, 0xa7, 0x69, 0xda, 0x77, 0x91,
+    0x8f, 0x37, 0x55, 0xe3, 0x38, 0x20, 0xb7, 0xfc, 0x2f, 0xa0, 0xd2, 0x9d,
+    0x4c, 0x55, 0x9f, 0xf9, 0x57, 0x58, 0xec, 0xfb, 0xff, 0xf8, 0x14, 0xef,
+    0x80, 0xf6, 0xf4, 0xd1, 0xa4, 0xe3, 0x0d, 0x76, 0x51, 0xa7, 0x2c, 0xa5,
+    0xe6, 0x80, 0xe5, 0xb6, 0x26, 0x94, 0x6b, 0x21, 0xa9, 0xb6, 0x37, 0x53,
+    0x1b, 0x94, 0xa9, 0x08, 0xd2, 0xef, 0x8a, 0x8d, 0xb5, 0xa3, 0x1d, 0x12,
+    0xc9, 0xae, 0x3b, 0x6e, 0x09, 0x5c, 0x1f, 0x70, 0x62, 0x5c, 0x7c, 0x4b,
+    0x47, 0x6f, 0x24, 0xff, 0xac, 0x1e, 0xa3, 0x89, 0x34, 0x4d, 0x7b, 0x6b,
+    0xba, 0x10, 0xf3, 0x87, 0x55, 0xef, 0xf2, 0xd9, 0x3f, 0xa7, 0xdc, 0xaf,
+    0x6b, 0x7b, 0xbd, 0x64, 0x3f, 0x6b, 0xe0, 0x40, 0xb1, 0xff, 0xc2, 0x18,
+    0x33, 0xa0, 0x4a, 0xe5, 0x81, 0xb5, 0xfd, 0x84, 0x69, 0x84, 0xd4, 0x49,
+    0x88, 0xfb, 0xf9, 0xb4, 0x44, 0xbc, 0x86, 0xba, 0x67, 0x74, 0xe3, 0x41,
+    0xe6, 0xf0, 0x2a, 0x28, 0xff, 0xf1, 0x1e, 0xbb, 0x4a, 0x39, 0x76, 0xd9,
+    0xb3, 0x4c, 0x4b, 0xec, 0x85, 0x9d, 0x8e, 0xba, 0xe4, 0x7e, 0xcd, 0x0a,
+    0xc5, 0x3e, 0x74, 0xdb, 0x47, 0x2c, 0xf8, 0xdf, 0x47, 0xf2, 0x1e, 0xee,
+    0xb9, 0x4c, 0x38, 0xf2, 0xf7, 0xee, 0x43, 0x17, 0xce, 0xba, 0xc6, 0x74,
+    0xdf, 0xe8, 0xc4, 0xd7, 0x22, 0x6d, 0x53, 0xb4, 0xed, 0x3b, 0xc8, 0xc7,
+    0x9b, 0xaa, 0xf1, 0x9c, 0x10, 0x5b, 0xfe, 0x17, 0xd0, 0x69, 0x4e, 0xa6,
+    0x2a, 0xcf, 0xfc, 0xab, 0xac, 0x76, 0x7d, 0xff, 0xfc, 0x0a, 0x77, 0xc0,
+    0x7b, 0x7a, 0x68, 0xd2, 0x71, 0x86, 0xbb, 0x28, 0xd3, 0x96, 0x52, 0xf3,
+    0x40, 0x72, 0xdb, 0x13, 0x4a, 0x35, 0x90, 0xd4, 0xdb, 0x1b, 0xa9, 0x8d,
+    0xca, 0x54, 0x84, 0x69, 0x77, 0xc5, 0x46, 0xda, 0xd1, 0x8e, 0x89, 0x64,
+    0xd7, 0x1d, 0xb7, 0x04, 0xae, 0x0f, 0xb8, 0x31, 0x2e, 0x3e, 0x25, 0xa3,
+    0xb7, 0x92, 0x7f, 0xd6, 0x0f, 0x51, 0xc4, 0x9a, 0x26, 0xbd, 0xb5, 0xdd,
+    0x08, 0x79, 0xc3, 0xaa, 0xf7, 0xf9, 0x6c, 0x9f, 0xd3, 0xee, 0x57, 0xb5,
+    0xbd, 0xde, 0xb2, 0x1f, 0xb5, 0xf0, 0x20, 0x58, 0xff, 0xe1, 0x0c, 0x19,
+    0xd0, 0x25, 0x72, 0xc0, 0xda, 0xfe, 0xc2, 0x34, 0xc2, 0x6a, 0x24, 0xc4,
+    0x7d, 0xfc, 0xda, 0x22, 0x5e, 0x43, 0x5d, 0x33, 0xba, 0x71, 0xa0, 0xf3,
+    0x78, 0x15, 0x14, 0x7f, 0xf8, 0x8f, 0x5d, 0xa5, 0x1c, 0xbb, 0x6c, 0xd9,
+    0xa6, 0x25, 0xf6, 0x42, 0xce, 0xc7, 0x5d, 0x72, 0x3f, 0x66, 0x85, 0x62,
+    0x9f, 0x3a, 0x6d, 0xa3, 0x96, 0x7c, 0x6f, 0xa3, 0xf9, 0x0f, 0x77, 0x5c,
+    0xa6, 0x1c, 0x79, 0x7b, 0xf7, 0x21, 0x8b, 0xe7, 0x5d, 0x63, 0x3a, 0x6f,
+    0xf4, 0x62, 0x6b, 0x91, 0x36, 0xa9, 0xda, 0x76, 0x9d, 0xe4, 0x63, 0xcd,
+    0xd5, 0x78, 0xce, 0x08, 0x2d, 0xff, 0x0b, 0xe8, 0x34, 0xa7, 0x53, 0x15,
+    0x67, 0xfe, 0x55, 0xd6, 0x3b, 0x3e, 0xff, 0xfe, 0x05, 0x3b, 0xe0, 0x3d,
+    0xbd, 0x34, 0x69, 0x38, 0xc3, 0x5d, 0x94, 0x69, 0xcb, 0x29, 0x79, 0xa0,
+    0x39, 0x6d, 0x89, 0xa5, 0x1a, 0xc8, 0x6a, 0x6d, 0x8d, 0xd4, 0xc6, 0xe5,
+    0x2a, 0x42, 0x34, 0xbb, 0xe2, 0xa3, 0x6d, 0x68, 0xc7, 0x44, 0xb2, 0x6b,
+    0x8e, 0xdb, 0x82, 0x57, 0x07, 0xdc, 0x18, 0x97, 0x1f, 0x12, 0xd1, 0xdb,
+    0xc9, 0x3f, 0xeb, 0x07, 0xa8, 0xe2, 0x4d, 0x13, 0x5e, 0xda, 0xee, 0x84,
+    0x3c, 0xe1, 0xd5, 0x7b, 0xfc, 0xb6, 0x4f, 0xe9, 0xf7, 0x2b, 0xda, 0xde,
+    0xef, 0x59, 0x0f, 0xda, 0xf8, 0x10, 0x2c, 0x7f, 0xf0, 0x86, 0x0c, 0xe8,
+    0x12, 0xb9, 0x60, 0x6d, 0x7f, 0x61, 0x1a, 0x61, 0x35, 0x12, 0x62, 0x3e,
+    0xfe, 0x6d, 0x11, 0x2f, 0x21, 0xae, 0x99, 0xdd, 0x38, 0xd0, 0x79, 0xbc,
+    0x0a, 0x8a, 0x3f, 0xfc, 0x47, 0xae, 0xd2, 0x8e, 0x5d, 0xb6, 0x6c, 0xd3,
+    0x12, 0xfb, 0x21, 0x67, 0x63, 0xae, 0xb9, 0x1f, 0xb3, 0x42, 0xb1, 0x4f,
+    0x9d, 0x36, 0xd1, 0xcb, 0x3e, 0x37, 0xd1, 0xfc, 0x87, 0xbb, 0xae, 0x53,
+    0x0e, 0x3c, 0xbd, 0xfb, 0x90, 0xc5, 0xf3, 0xae, 0xb1, 0x9d, 0x37, 0xfa,
+    0x31, 0x35, 0xc8, 0x9b, 0x54, 0xed, 0x3b, 0x4e, 0xf2, 0x31, 0xe6, 0xea,
+    0xbc, 0x67, 0x04, 0x16, 0xff, 0x85, 0xf4, 0x1a, 0x53, 0xa9, 0x8a, 0xb3,
+    0xff, 0x2a, 0xeb, 0x1d, 0x9f, 0x7f, 0xff, 0x02, 0x9d, 0xf0, 0x1e, 0xde,
+    0x9a, 0x34, 0x9c, 0x61, 0xae, 0xca, 0x34, 0xe5, 0x94, 0xbc, 0xd0, 0x1c,
+    0xb6, 0xc4, 0xd2, 0x8d, 0x64, 0x35, 0x36, 0xc6, 0xea, 0x63, 0x72, 0x95,
+    0x21, 0x1a, 0x5d, 0xf1, 0x51, 0xb6, 0xb4, 0x63, 0xa2, 0x59, 0x35, 0xc7,
+    0x6d, 0xc1, 0x2b, 0x83, 0xee, 0x0c, 0x4b, 0x8f, 0x89, 0x68, 0xed, 0xe4,
+    0x9f, 0xf5, 0x83, 0xd4, 0x71, 0x26, 0x89, 0xaf, 0x6d, 0x77, 0x42, 0x1e,
+    0x70, 0xea, 0xbd, 0xfe, 0x5b, 0x27, 0xf4, 0xfb, 0x95, 0xed, 0x6f, 0x77,
+    0xac, 0x87, 0xed, 0x7c, 0x08, 0x16, 0x3f, 0xf8, 0x43, 0x06, 0x74, 0x09,
+    0x5c, 0xb0, 0x36, 0xbf, 0xb0, 0x8d, 0x30, 0x9a, 0x89, 0x31, 0x1f, 0x7f,
+    0x36, 0x88, 0x97, 0x90, 0xd7, 0x4c, 0xee, 0x9c, 0x68, 0x3c, 0xde, 0x05,
+    0x45, 0x1f, 0xfe, 0x23, 0xd7, 0x69, 0x47, 0x2e, 0xdb, 0x36, 0x69, 0x89,
+    0x7d, 0x90, 0xb3, 0xb1, 0xd7, 0x5c, 0x8f, 0xd9, 0xa1, 0x58, 0xa7, 0xce,
+    0x9b, 0x68, 0xe5, 0x9f, 0x1b, 0xe8, 0xfe, 0x43, 0xdd, 0xd7, 0x29, 0x87,
+    0x1e, 0x5e, 0xfd, 0xc8, 0x62, 0xf9, 0xd7, 0x58, 0xce, 0x9b, 0xfd, 0x18,
+    0x9a, 0xe4, 0x4d, 0xaa, 0x76, 0x9d, 0xa7, 0x79, 0x18, 0xf3, 0x75, 0x5e,
+    0x33, 0x82, 0x0b, 0x7f, 0xc2, 0xfa, 0x0d, 0x29, 0xd4, 0xc5, 0x59, 0xff,
+    0x95, 0x75, 0x8e, 0xcf, 0xbf, 0xff, 0x81, 0x4e, 0xf8, 0x0f, 0x6f, 0x4d,
+    0x1a, 0x4e, 0x30, 0xd7, 0x65, 0x1a, 0x72, 0xca, 0x5e, 0x68, 0x0e, 0x5b,
+    0x62, 0x69, 0x46, 0xb2, 0x1a, 0x9b, 0x63, 0x75, 0x31, 0xb9, 0x4a, 0x90,
+    0x8d, 0x2e, 0xf8, 0xa8, 0xdb, 0x5a, 0x31, 0xd1, 0x2c, 0x9a, 0xe3, 0xb6,
+    0xe0, 0x95, 0xc1, 0xf7, 0x06, 0x25, 0xc7, 0xc4, 0xb4, 0x76, 0xf2, 0x4f,
+    0xfa, 0xc1, 0xea, 0x38, 0x93, 0x44, 0xd7, 0xb6, 0xbb, 0xa1, 0x0f, 0x38,
+    0x75, 0x5e, 0xff, 0x2d, 0x93, 0xfa, 0x7d, 0xca, 0xf6, 0xb7, 0xbb, 0xd6,
+    0x43, 0xf6, 0xbe, 0x04, 0x0b, 0x1f, 0xfc, 0x21, 0x83, 0x3a, 0x04, 0xae,
+    0x58, 0x1b, 0x5f, 0xd8, 0x46, 0x98, 0x4d, 0x44, 0x98, 0x8f, 0xbf, 0x9b,
+    0x44, 0x4b, 0xc8, 0x6b, 0xa6, 0x77, 0x4e, 0x34, 0x1e, 0x6f, 0x02, 0xa2,
+    0x8f, 0xff, 0x11, 0xeb, 0xb4, 0xa3, 0x97, 0x6d, 0x9b, 0x34, 0xc4, 0xbe,
+    0xc8, 0x59, 0xd8, 0xeb, 0xae, 0x47, 0xec, 0xd0, 0xac, 0x53, 0xe7, 0x4d,
+    0xb4, 0x72, 0xcf, 0x8d, 0xf4, 0x7f, 0x21, 0xee, 0xeb, 0x94, 0xc3, 0x8f,
+    0x2f, 0x7e, 0xe4, 0x31, 0x7c, 0xeb, 0xac, 0x67, 0x4d, 0xfe, 0x8c, 0x4d,
+    0x72, 0x26, 0xd5, 0x3b, 0x4e, 0xd3, 0xbc, 0x8c, 0x79, 0xba, 0xaf, 0x19,
+    0xc1, 0x05, 0xbf, 0xe1, 0x7d, 0x06, 0x94, 0xea, 0x62, 0xac, 0xff, 0xca,
+    0xba, 0xc7, 0x67, 0xdf, 0xff, 0xc0, 0xa7, 0x7c, 0x07, 0xb7, 0xa6, 0x8d,
+    0x27, 0x18, 0x6b, 0xb2, 0x8d, 0x39, 0x65, 0x2f, 0x34, 0x07, 0x2d, 0xb1,
+    0x34, 0xa3, 0x59, 0x0d, 0x4d, 0xb1, 0xba, 0x98, 0xdc, 0xa5, 0x48, 0x46,
+    0x97, 0x7c, 0x54, 0x6d, 0xad, 0x18, 0xe8, 0x96, 0x4d, 0x71, 0xdb, 0x70,
+    0x4a, 0xe0, 0xfb, 0x83, 0x12, 0xe3, 0xe2, 0x5a, 0x3b, 0x79, 0x27, 0xfd,
+    0x60, 0xf5, 0x1c, 0x49, 0xa2, 0x6b, 0xdb, 0x5d, 0xd0, 0x87, 0x9c, 0x3a,
+    0xaf, 0x7f, 0x96, 0xc9, 0xfd, 0x3e, 0xe5, 0x7b, 0x5b, 0xdd, 0xeb, 0x21,
+    0xfb, 0x5f, 0x02, 0x05, 0x8f, 0xfe, 0x10, 0xc1, 0x9d, 0x02, 0x57, 0x2c,
+    0x0d, 0xaf, 0xec, 0x23, 0x4c, 0x26, 0xa2, 0x4c, 0x47, 0xdf, 0xcd, 0xa2,
+    0x25, 0xe4, 0x35, 0xd3, 0x3b, 0xa7, 0x1a, 0x0f, 0x37, 0x81, 0x51, 0x47,
+    0xff, 0x88, 0xf5, 0xda, 0x51, 0xcb, 0xb6, 0xcd, 0x9a, 0x62, 0x5f, 0x64,
+    0x2c, 0xec, 0x75, 0xd7, 0x23, 0xf6, 0x68, 0x56, 0x29, 0xf3, 0xa6, 0xda,
+    0x39, 0x67, 0xc6, 0xfa, 0x3f, 0x90, 0xf7, 0x75, 0xca, 0x61, 0xc7, 0x97,
+    0xbf, 0x72, 0x18, 0xbe, 0x75, 0xd6, 0x33, 0xa6, 0xff, 0x46, 0x26, 0xb9,
+    0x13, 0x6a, 0x9d, 0xa7, 0x69, 0xde, 0x46, 0x3c, 0xdd, 0x57, 0x8c, 0xe0,
+    0x82, 0xdf, 0xf0, 0xbe, 0x83, 0x4a, 0x75, 0x31, 0x56, 0x7f, 0xe5, 0x5d,
+    0x63, 0xb3, 0xef, 0xff, 0xe0, 0x53, 0xbe, 0x03, 0xdb, 0xd3, 0x46, 0x93,
+    0x8c, 0x35, 0xd9, 0x46, 0x9c, 0xb2, 0x97, 0x9a, 0x03, 0x96, 0xd8, 0x9a,
+    0x51, 0xac, 0x86, 0xa6, 0xd8, 0xdd, 0x4c, 0x6e, 0x52, 0xa4, 0x23, 0x4b,
+    0xbe, 0x2a, 0x36, 0xd6, 0x8c, 0x74, 0x4b, 0x26, 0xb8, 0xed, 0xb8, 0x25,
+    0x70, 0x7d, 0xc1, 0x89, 0x71, 0xf1, 0x2d, 0x1d, 0xbc, 0x93, 0xfe, 0xb0,
+    0x7a, 0x8e, 0x24, 0xd1, 0x35, 0xed, 0xae, 0xe8, 0x43, 0xce, 0x1d, 0x57,
+    0xbf, 0xcb, 0x64, 0xfe, 0x9f, 0x72, 0xbd, 0xad, 0xee, 0xf5, 0x90, 0xfd,
+    0xaf, 0x81, 0x02, 0xc7, 0xff, 0x08, 0x60, 0xce, 0x81, 0x2b, 0x96, 0x06,
+    0xd7, 0xf6, 0x11, 0xa6, 0x13, 0x51, 0x26, 0x23, 0xef, 0xe6, 0xd1, 0x12,
+    0xf2, 0x1a, 0xe9, 0x9d, 0xd3, 0x8d, 0x07, 0x9b, 0xc0, 0xa8, 0xa3, 0xff,
+    0xc4, 0x7a, 0xed, 0x28, 0xe5, 0xdb, 0x66, 0xcd, 0x31, 0x2f, 0xb2, 0x16,
+    0x76, 0x3a, 0xeb, 0x91, 0xfb, 0x34, 0x2b, 0x14, 0xf9, 0xd3, 0x6d, 0x1c,
+    0xb3, 0xe3, 0x7d, 0x1f, 0xc8, 0x7b, 0xba, 0xe5, 0x30, 0xe3, 0xcb, 0xdf,
+    0xb9, 0x0c, 0x5f, 0x3a, 0xeb, 0x19, 0xd3, 0x7f, 0xa3, 0x13, 0x5c, 0x89,
+    0xb5, 0x4e, 0xd3, 0xb4, 0xef, 0x23, 0x1e, 0x6e, 0xab, 0xc6, 0x70, 0x41,
+    0x6f, 0xf8, 0x5f, 0x41, 0xa5, 0x3a, 0x98, 0xab, 0x3f, 0xf2, 0xae, 0xb1,
+    0xd9, 0xf7, 0xff, 0xf0, 0x29, 0xdf, 0x01, 0xed, 0xe9, 0xa3, 0x49, 0xc6,
+    0x1a, 0xec, 0xa3, 0x4e, 0x59, 0x4b, 0xcd, 0x01, 0xcb, 0x6c, 0x4d, 0x28,
+    0xd6, 0x43, 0x53, 0x6c, 0x6e, 0xa6, 0x37, 0x29, 0x52, 0x11, 0xa5, 0xdf,
+    0x15, 0x1b, 0x6b, 0x46, 0x3a, 0x25, 0x93, 0x5c, 0x76, 0xdc, 0x12, 0xb8,
+    0x3e, 0xe0, 0xc4, 0xb8, 0xf8, 0x96, 0x8e, 0xde, 0x49, 0xff, 0x58, 0x3d,
+    0x47, 0x12, 0x68, 0x9a, 0xf6, 0xd7, 0x74, 0x21, 0xe7, 0x0e, 0xab, 0xdf,
+    0xe5, 0xb2, 0x7f, 0x4f, 0xb9, 0x5e, 0xd6, 0xf7, 0x7a, 0xc8, 0x7e, 0xd7,
+    0xc0, 0x81, 0x63, 0xff, 0x84, 0x30, 0x67, 0x40, 0x95, 0xcb, 0x03, 0x6b,
+    0xfb, 0x08, 0xd3, 0x09, 0xa8, 0x93, 0x11, 0xf7, 0xf3, 0x68, 0x89, 0x79,
+    0x0d, 0x74, 0xce, 0xe9, 0xc6, 0x83, 0xcd, 0xe0, 0x54, 0x51, 0xff, 0xe2,
+    0x3d, 0x76, 0x94, 0x72, 0xed, 0xb3, 0x66, 0x98, 0x97, 0xd9, 0x0b, 0x3b,
+    0x1d, 0x75, 0xc8, 0xfd, 0x9a, 0x15, 0x8a, 0x7c, 0xe9, 0xb6, 0x8e, 0x59,
+    0xf1, 0xbe, 0x8f, 0xe4, 0x3d, 0xdd, 0x72, 0x98, 0x71, 0xe5, 0xef, 0xdc,
+    0x86, 0x2f, 0x9d, 0x75, 0x8c, 0xe9, 0xbf, 0xd1, 0x89, 0xae, 0x44, 0xda,
+    0xa7, 0x69, 0xda, 0x77, 0x91, 0x8f, 0x37, 0x55, 0xe3, 0x38, 0x20, 0xb7,
+    0xfc, 0x2f, 0xa0, 0xd2, 0x9d, 0x4c, 0x55, 0x9f, 0xf9, 0x57, 0x58, 0xec,
+    0xfb, 0xff, 0xf8, 0x14, 0xef, 0x80, 0xf6, 0xf4, 0xd1, 0xa4, 0xe3, 0x0d,
+    0x76, 0x51, 0xa7, 0x2c, 0xa5, 0xe6, 0x80, 0xe5, 0xb6, 0x26, 0x94, 0x6b,
+    0x21, 0xa9, 0xb6, 0x37, 0x53, 0x1b, 0x94, 0xa9, 0x08, 0xd2, 0xef, 0x8a,
+    0x8d, 0xb5, 0xa3, 0x1d, 0x12, 0xc9, 0xae, 0x3b, 0x6e, 0x09, 0x5c, 0x1f,
+    0x70, 0x62, 0x5c, 0x7c, 0x4b, 0x47, 0x6f, 0x24, 0xff, 0xac, 0x1e, 0xa3,
+    0x89, 0x34, 0x4d, 0x7b, 0x6b, 0xba, 0x10, 0xf3, 0x87, 0x55, 0xef, 0xf2,
+    0xd9, 0x3f, 0xa7, 0xdc, 0xaf, 0x6b, 0x7b, 0xbd, 0x64, 0x3f, 0x6b, 0xe0,
+    0x40, 0xb1, 0xff, 0xc2, 0x18, 0x33, 0xa0, 0x4a, 0xe5, 0x81, 0xb5, 0xfd,
+    0x84, 0x69, 0x84, 0xd4, 0x49, 0x88, 0xfb, 0xf9, 0xb4, 0x44, 0xbc, 0x86,
+    0xba, 0x67, 0x74, 0xe3, 0x41, 0xe6, 0xf0, 0x2a, 0x28, 0xff, 0xf1, 0x1e,
+    0xbb, 0x4a, 0x39, 0x76, 0xd9, 0xb3, 0x4c, 0x4b, 0xec, 0x85, 0x9d, 0x8e,
+    0xba, 0xe4, 0x7e, 0xcd, 0x0a, 0xc5, 0x3e, 0x74, 0xdb, 0x47, 0x2c, 0xf8,
+    0xdf, 0x47, 0xf2, 0x1e, 0xee, 0xb9, 0x4c, 0x38, 0xf2, 0xf7, 0xee, 0x43,
+    0x17, 0xce, 0xba, 0xc6, 0x74, 0xdf, 0xe8, 0xc4, 0xd7, 0x22, 0x6d, 0x53,
+    0xb4, 0xed, 0x3b, 0xc8, 0xc7, 0x9b, 0xaa, 0xf1, 0x9c, 0x10, 0x5b, 0xfe,
+    0x17, 0xd0, 0x69, 0x4e, 0xa6, 0x2a, 0xcf, 0xfc, 0xab, 0xac, 0x76, 0x7d,
+    0xff, 0xfc, 0x0a, 0x77, 0xc0, 0x7b, 0x7a, 0x68, 0xd2, 0x71, 0x86, 0xbb,
+    0x28, 0xd3, 0x96, 0x52, 0xf3, 0x40, 0x72, 0xdb, 0x13, 0x4a, 0x35, 0x90,
+    0xd4, 0xdb, 0x1b, 0xa9, 0x8d, 0xca, 0x54, 0x84, 0x69, 0x77, 0xc5, 0x46,
+    0xda, 0xd1, 0x8e, 0x89, 0x64, 0xd7, 0x1d, 0xb7, 0x04, 0xae, 0x0f, 0xb8,
+    0x31, 0x2e, 0x3e, 0x25, 0xa3, 0xb7, 0x92, 0x7f, 0xd6, 0x0f, 0x51, 0xc4,
+    0x9a, 0x26, 0xbd, 0xb5, 0xdd, 0x08, 0x79, 0xc3, 0xaa, 0xf7, 0xf9, 0x6c,
+    0x9f, 0xd3, 0xee, 0x57, 0xb5, 0xbd, 0xde, 0xb2, 0x1f, 0xb5, 0xf0, 0x20,
+    0x58, 0xff, 0xe1, 0x0c, 0x19, 0xd0, 0x25, 0x72, 0xc0, 0xda, 0xfe, 0xc2,
+    0x34, 0xc2, 0x6a, 0x24, 0xc4, 0x7d, 0xfc, 0xda, 0x22, 0x5e, 0x43, 0x5d,
+    0x33, 0xba, 0x71, 0xa0, 0xf3, 0x78, 0x15, 0x14, 0x7f, 0xf8, 0x8f, 0x5d,
+    0xa5, 0x1c, 0xbb, 0x6c, 0xd9, 0xa6, 0x25, 0xf6, 0x42, 0xce, 0xc7, 0x5d,
+    0x72, 0x3f, 0x66, 0x85, 0x62, 0x9f, 0x3a, 0x6d, 0xa3, 0x96, 0x7c, 0x6f,
+    0xa3, 0xf9, 0x0f, 0x77, 0x5c, 0xa6, 0x1c, 0x79, 0x7b, 0xf7, 0x21, 0x8b,
+    0xe7, 0x5d, 0x63, 0x3a, 0x6f, 0xf4, 0x62, 0x6b, 0x91, 0x36, 0xa9, 0xda,
+    0x76, 0x9d, 0xe4, 0x63, 0xcd, 0xd5, 0x78, 0xce, 0x08, 0x2d, 0xff, 0x0b,
+    0xe8, 0x34, 0xa7, 0x53, 0x15, 0x67, 0xfe, 0x55, 0xd6, 0x3b, 0x3e, 0xff,
+    0xfe, 0x05, 0x3b, 0xe0, 0x3d, 0xbd, 0x34, 0x69, 0x38, 0xc3, 0x5d, 0x94,
+    0x69, 0xcb, 0x29, 0x79, 0xa0, 0x39, 0x6d, 0x89, 0xa5, 0x1a, 0xc8, 0x6a,
+    0x6d, 0x8d, 0xd4, 0xc6, 0xe5, 0x2a, 0x42, 0x34, 0xbb, 0xe2, 0xa3, 0x6d,
+    0x68, 0xc7, 0x44, 0xb2, 0x6b, 0x8e, 0xdb, 0x82, 0x57, 0x07, 0xdc, 0x18,
+    0x97, 0x1f, 0x12, 0xd1, 0xdb, 0xc9, 0x3f, 0xeb, 0x07, 0xa8, 0xe2, 0x4d,
+    0x13, 0x5e, 0xda, 0xee, 0x84, 0x3c, 0xe1, 0xd5, 0x7b, 0xfc, 0xb6, 0x4f,
+    0xe9, 0xf7, 0x2b, 0xda, 0xde, 0xef, 0x59, 0x0f, 0xda, 0xf8, 0x10, 0x2c,
+    0x7f, 0xf0, 0x86, 0x0c, 0xe8, 0x12, 0xb9, 0x60, 0x6d, 0x7f, 0x61, 0x1a,
+    0x61, 0x35, 0x12, 0x62, 0x3e, 0xfe, 0x6d, 0x11, 0x2f, 0x21, 0xae, 0x99,
+    0xdd, 0x38, 0xd0, 0x79, 0xbc, 0x0a, 0x8a, 0x3f, 0xfc, 0x47, 0xae, 0xd2,
+    0x8e, 0x5d, 0xb6, 0x6c, 0xd3, 0x12, 0xfb, 0x21, 0x67, 0x63, 0xae, 0xb9,
+    0x1f, 0xb3, 0x42, 0xb1, 0x4f, 0x9d, 0x36, 0xd1, 0xcb, 0x3e, 0x37, 0xd1,
+    0xfc, 0x87, 0xbb, 0xae, 0x53, 0x0e, 0x3c, 0xbd, 0xfb, 0x90, 0xc5, 0xf3,
+    0xae, 0xb1, 0x9d, 0x37, 0xfa, 0x31, 0x35, 0xc8, 0x9b, 0x54, 0xed, 0x3b,
+    0x4e, 0xf2, 0x31, 0xe6, 0xea, 0xbc, 0x67, 0x04, 0x16, 0xff, 0x85, 0xf4,
+    0x1a, 0x53, 0xa9, 0x8a, 0xb3, 0xff, 0x2a, 0xeb, 0x1d, 0x9f, 0x7f, 0xff,
+    0x08,
+};
+static_assert(sizeof(kBytesTestReadSymbol11) == kNumBytesTestReadSymbol11, "");
+
+// The kBytesTestReadSymbol12[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][13] = {
+//   // pmf: 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12, 1/12,
+//   // 1/12
+//   { 32768 - 2731, 32768 - 5461, 32768 - 8192, 32768 - 10923, 32768 - 13653,
+//     32768 - 16384, 32768 - 19115, 32768 - 21845, 32768 - 24576,
+//     32768 - 27307, 32768 - 30037, 0, 0 },
+//   // pmf: 3/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24,
+//   // 1/24
+//   { 32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288, 32768 - 15019,
+//     32768 - 17749, 32768 - 20480, 32768 - 23211, 32768 - 25941,
+//     32768 - 28672, 32768 - 31403, 0, 0 },
+//   // pmf: 1/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24, 2/24,
+//   // 3/24
+//   { 32768 - 1365, 32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288,
+//     32768 - 15019, 32768 - 17749, 32768 - 20480, 32768 - 23211,
+//     32768 - 25941, 32768 - 28672, 0, 0 },
+//   // pmf: 1/24, 2/24, 2/24, 2/24, 2/24, 3/24, 3/24, 2/24, 2/24, 2/24, 2/24,
+//   // 1/24
+//   { 32768 - 1365, 32768 - 4096, 32768 - 6827, 32768 - 9557, 32768 - 12288,
+//     32768 - 16384, 32768 - 20480, 32768 - 23211, 32768 - 25941,
+//     32768 - 28672, 32768 - 31403, 0, 0 },
+// };
+// constexpr int kSymbols[24][4] = { { 0, 6, 11, 5 },   //
+//                                   { 1, 7, 10, 4 },   //
+//                                   { 2, 8, 9, 3 },    //
+//                                   { 3, 9, 8, 2 },    //
+//                                   { 4, 10, 7, 1 },   //
+//                                   { 5, 11, 6, 0 },   //
+//                                   { 6, 0, 5, 11 },   //
+//                                   { 7, 1, 4, 10 },   //
+//                                   { 8, 2, 3, 9 },    //
+//                                   { 9, 3, 2, 8 },    //
+//                                   { 10, 4, 1, 7 },   //
+//                                   { 11, 5, 0, 6 },   //
+//                                   { 0, 0, 11, 9 },   //
+//                                   { 2, 1, 10, 7 },   //
+//                                   { 4, 3, 8, 5 },    //
+//                                   { 6, 5, 6, 3 },    //
+//                                   { 8, 7, 4, 1 },    //
+//                                   { 10, 9, 2, 10 },  //
+//                                   { 1, 0, 11, 8 },   //
+//                                   { 3, 2, 9, 6 },    //
+//                                   { 5, 4, 7, 4 },    //
+//                                   { 7, 6, 5, 2 },    //
+//                                   { 9, 8, 3, 6 },    //
+//                                   { 11, 10, 1, 5 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 80; ++i) {
+//   for (int j = 0; j < 24; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 12);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol12 = 3473;
+constexpr uint8_t kBytesTestReadSymbol12[] = {
+    0x0d, 0x17, 0xf5, 0xbd, 0x05, 0xd0, 0x9c, 0x5d, 0x10, 0xc5, 0x9e, 0xc4,
+    0x9f, 0xc6, 0xf4, 0x7d, 0xce, 0x67, 0x97, 0x49, 0xd1, 0x05, 0x54, 0xab,
+    0xda, 0x22, 0x5b, 0xbc, 0x9c, 0x11, 0xc8, 0x0b, 0xe9, 0x6d, 0xb1, 0x8a,
+    0x17, 0x06, 0x92, 0xed, 0xd4, 0x61, 0x48, 0x01, 0x64, 0x43, 0x65, 0x65,
+    0xfc, 0x35, 0x9d, 0xbb, 0x68, 0x3f, 0x77, 0xbc, 0x8d, 0xd9, 0x3b, 0x48,
+    0x77, 0x58, 0x2f, 0x19, 0xfa, 0x73, 0xa6, 0xc3, 0x65, 0x96, 0x6c, 0x9d,
+    0x99, 0xb8, 0x65, 0x2b, 0x94, 0x11, 0x21, 0xf4, 0x95, 0xa4, 0xcd, 0xf2,
+    0xbf, 0x65, 0x79, 0x34, 0x4b, 0xf6, 0x5c, 0xeb, 0xca, 0x07, 0x65, 0x4f,
+    0xae, 0x67, 0xd8, 0xdf, 0xec, 0xc9, 0xd2, 0x26, 0x2e, 0xac, 0xea, 0xa2,
+    0xbd, 0x0d, 0x79, 0x27, 0x91, 0xf5, 0x84, 0x89, 0xf9, 0x2a, 0xb3, 0x5e,
+    0x48, 0x4b, 0x2b, 0x89, 0xc0, 0xa5, 0x9f, 0x94, 0x07, 0x82, 0x36, 0x11,
+    0x65, 0x4d, 0xb0, 0xde, 0xac, 0xde, 0xac, 0xc0, 0x35, 0x7f, 0xf3, 0x9b,
+    0x01, 0x0c, 0x35, 0x8b, 0xb5, 0x22, 0xb8, 0xea, 0x1c, 0xab, 0xbe, 0x08,
+    0xd9, 0x23, 0x0a, 0x37, 0x95, 0x36, 0x3d, 0x28, 0xb3, 0x19, 0x34, 0x3a,
+    0x47, 0xf8, 0x45, 0x33, 0x7a, 0x65, 0xae, 0x80, 0x48, 0x01, 0x20, 0xe8,
+    0xcd, 0xb7, 0xce, 0xf7, 0xee, 0xd1, 0x50, 0x39, 0xec, 0xa6, 0x8b, 0xa0,
+    0xb5, 0x56, 0x76, 0x1a, 0xb4, 0x6b, 0x31, 0xcf, 0x32, 0x0f, 0xb1, 0xba,
+    0xb3, 0xa4, 0xb7, 0x34, 0xfe, 0x86, 0x87, 0xa7, 0x44, 0x70, 0x3b, 0x9e,
+    0x94, 0xc5, 0x43, 0x82, 0xf1, 0x1a, 0xa1, 0x10, 0x05, 0x7c, 0x04, 0x63,
+    0x5a, 0xfe, 0xc2, 0xb6, 0x15, 0x07, 0x3f, 0xb0, 0x3c, 0x43, 0x74, 0x33,
+    0xec, 0xb8, 0xe0, 0xf5, 0x79, 0x48, 0x7c, 0x50, 0x4f, 0x4b, 0xb9, 0x08,
+    0x33, 0xfd, 0x54, 0xd5, 0x6f, 0xdf, 0xca, 0xfe, 0x38, 0xa1, 0xeb, 0xa9,
+    0xaf, 0xa5, 0x8f, 0xcf, 0xb3, 0xda, 0x77, 0x3f, 0x63, 0xcb, 0x98, 0x2b,
+    0x71, 0x56, 0x60, 0xb4, 0x5c, 0x7d, 0x81, 0x85, 0xf3, 0x64, 0x9f, 0xf3,
+    0xc2, 0xec, 0x2a, 0x27, 0x9b, 0x5e, 0x39, 0x30, 0x10, 0x0d, 0x43, 0xdb,
+    0x9f, 0x7b, 0x8f, 0xb8, 0x09, 0xe2, 0x55, 0xb3, 0xc4, 0xb1, 0xeb, 0x23,
+    0xcd, 0x32, 0xde, 0x58, 0xc2, 0x35, 0xda, 0x5c, 0x9a, 0xf8, 0x2d, 0xc6,
+    0x19, 0x46, 0x64, 0x66, 0x5a, 0xdb, 0x53, 0xc8, 0x14, 0x41, 0xcc, 0x0c,
+    0x3f, 0xff, 0x3e, 0xbe, 0x29, 0xba, 0x5f, 0x68, 0xa9, 0x31, 0x39, 0x79,
+    0x2a, 0xfe, 0x14, 0x92, 0x8f, 0x2b, 0x31, 0xf1, 0x0a, 0x25, 0xd8, 0x22,
+    0xe1, 0xc7, 0xcd, 0xda, 0xea, 0x88, 0xfa, 0x6a, 0xb0, 0x69, 0x77, 0xf6,
+    0xd6, 0x46, 0xb9, 0xe6, 0x53, 0x09, 0x48, 0x65, 0xbd, 0xe6, 0xf8, 0xc0,
+    0x04, 0x71, 0x26, 0x21, 0xe8, 0xf9, 0xc1, 0x71, 0x73, 0x6b, 0x3d, 0x73,
+    0x16, 0x66, 0x38, 0xae, 0x59, 0xb9, 0xe3, 0x34, 0x8f, 0x17, 0x3c, 0x16,
+    0xaa, 0x3f, 0x61, 0x49, 0xb3, 0x06, 0xcc, 0xb3, 0xcb, 0x7e, 0x42, 0xf1,
+    0x2a, 0x0e, 0xb2, 0xcb, 0x1d, 0xf0, 0x0f, 0xc9, 0x20, 0xb1, 0x80, 0xce,
+    0x08, 0xb9, 0xfa, 0xca, 0x3c, 0xd5, 0x67, 0x47, 0x36, 0x17, 0xc1, 0xf7,
+    0x9d, 0x97, 0x79, 0x75, 0xee, 0xb0, 0xed, 0xfc, 0xd0, 0xdf, 0xc8, 0xa2,
+    0xc1, 0xae, 0x51, 0x53, 0x88, 0x05, 0x95, 0x73, 0x7e, 0xd9, 0x3b, 0x9d,
+    0xb0, 0x08, 0x37, 0xff, 0x51, 0x6f, 0xf9, 0xad, 0x60, 0xa5, 0x3a, 0xd6,
+    0xba, 0xea, 0xf6, 0xea, 0x91, 0x2e, 0x5a, 0xa9, 0xbf, 0xe2, 0x52, 0x46,
+    0x0c, 0xbd, 0x28, 0x2d, 0xa8, 0x5f, 0xc8, 0x41, 0x31, 0x53, 0x7a, 0x9f,
+    0xfa, 0x73, 0x06, 0xc5, 0xae, 0x59, 0x8d, 0xe3, 0x0d, 0xfa, 0x99, 0x7f,
+    0xee, 0xe4, 0x82, 0xd4, 0x36, 0x68, 0x09, 0x92, 0x09, 0xef, 0x70, 0x89,
+    0xc6, 0xfa, 0xc7, 0x7e, 0x0f, 0x24, 0x8e, 0xad, 0x4e, 0xd9, 0x4c, 0x11,
+    0xe7, 0x7d, 0x98, 0xf0, 0x80, 0x42, 0x0b, 0x86, 0x8d, 0x8e, 0x85, 0x97,
+    0xd2, 0x11, 0x0f, 0x04, 0x59, 0xaf, 0xa5, 0xec, 0xda, 0x75, 0x64, 0x51,
+    0x22, 0x7e, 0x38, 0x4b, 0xca, 0x9e, 0x82, 0x71, 0x72, 0x8d, 0x4c, 0xca,
+    0xe1, 0x77, 0xe5, 0xe0, 0x9d, 0x64, 0x01, 0x48, 0x49, 0xcd, 0x3b, 0x90,
+    0xd8, 0x9e, 0x15, 0x22, 0x76, 0xe0, 0x57, 0x06, 0x06, 0xaf, 0x2c, 0x09,
+    0xce, 0x4c, 0xfa, 0x8b, 0xbf, 0xa1, 0x1b, 0xe3, 0xe7, 0xa5, 0xa0, 0xc0,
+    0xc8, 0x4c, 0x79, 0x1b, 0xeb, 0x5d, 0xb8, 0x3b, 0x1c, 0x3f, 0xbc, 0x11,
+    0x8f, 0xa0, 0x08, 0x2b, 0xd3, 0xe3, 0xca, 0xbc, 0x41, 0xc2, 0xa4, 0x4e,
+    0xdc, 0x0a, 0xe1, 0x06, 0xef, 0x55, 0x13, 0xb3, 0xdd, 0xfd, 0xe2, 0x89,
+    0x5f, 0xb5, 0xf6, 0xa9, 0xd7, 0xae, 0xc1, 0x14, 0xb6, 0x19, 0xd8, 0x5b,
+    0x0f, 0x9a, 0xb0, 0xed, 0xc5, 0xc7, 0xa8, 0xa6, 0x08, 0x5a, 0x00, 0xad,
+    0xf5, 0x9c, 0xb9, 0xd9, 0x45, 0x46, 0xf0, 0x9e, 0x2d, 0x55, 0xc6, 0x08,
+    0x60, 0x0d, 0x9e, 0xa7, 0x68, 0xb6, 0xf7, 0xf3, 0xa9, 0x84, 0x7e, 0x63,
+    0xe8, 0x48, 0x03, 0x1c, 0x15, 0x97, 0x94, 0xda, 0x04, 0xb2, 0xd0, 0x09,
+    0xa5, 0x62, 0x21, 0x70, 0x88, 0x9f, 0xf5, 0x0c, 0x91, 0x0d, 0xbf, 0x69,
+    0xe1, 0x6b, 0x4f, 0xc2, 0xf2, 0x32, 0xe1, 0x4b, 0xad, 0x58, 0xea, 0x0c,
+    0x07, 0x13, 0x4a, 0x1b, 0x87, 0x6d, 0x6e, 0x2f, 0xb6, 0xc6, 0x30, 0x1e,
+    0x2d, 0x1d, 0x5c, 0xdf, 0xd2, 0x5a, 0x88, 0xc8, 0x1c, 0xd9, 0xc3, 0x91,
+    0x04, 0x45, 0x63, 0x11, 0x44, 0x35, 0x7f, 0x46, 0xf4, 0xd0, 0xd1, 0x73,
+    0x9c, 0xae, 0x85, 0x5e, 0xda, 0xc7, 0xce, 0xb5, 0xbb, 0x3a, 0xb4, 0x67,
+    0xa5, 0xad, 0xc6, 0x5e, 0x12, 0xc7, 0xc5, 0x72, 0xfc, 0x35, 0x2e, 0xae,
+    0x46, 0x81, 0x22, 0x56, 0x6d, 0xc9, 0x36, 0x43, 0x17, 0x6b, 0x4d, 0x81,
+    0xd6, 0x59, 0x35, 0x90, 0x3a, 0xd2, 0xde, 0x79, 0xbd, 0x21, 0xc4, 0x56,
+    0xcb, 0x59, 0x3b, 0xe7, 0xb3, 0xab, 0x92, 0xce, 0x65, 0xc7, 0x20, 0xde,
+    0xde, 0xb1, 0x94, 0xac, 0x1a, 0x23, 0xa4, 0x14, 0x56, 0x32, 0xc0, 0x9f,
+    0x48, 0x31, 0xa6, 0x95, 0xc4, 0xb8, 0xf3, 0x9c, 0x8d, 0x34, 0x03, 0xc3,
+    0x62, 0x63, 0x38, 0x15, 0x71, 0x08, 0x5e, 0x1b, 0xc0, 0xf2, 0x54, 0x13,
+    0x66, 0x01, 0xf1, 0x38, 0xd9, 0x61, 0xf3, 0xdb, 0xd4, 0x83, 0x98, 0x3e,
+    0xaa, 0xe1, 0xca, 0x2d, 0xfb, 0x6d, 0x02, 0xac, 0xf2, 0xa6, 0x04, 0x09,
+    0xeb, 0xcb, 0xaf, 0xd5, 0x9d, 0x3d, 0xd7, 0xc2, 0xc1, 0x6f, 0xec, 0x53,
+    0x65, 0x0e, 0x40, 0x77, 0x03, 0xcd, 0x79, 0x0a, 0x94, 0x27, 0x6b, 0x6f,
+    0x32, 0xb3, 0xdb, 0x3e, 0x38, 0xe2, 0xd2, 0xca, 0x9b, 0x9e, 0x24, 0xc7,
+    0x35, 0xfd, 0xc1, 0x86, 0x78, 0xd9, 0xc3, 0xfe, 0x03, 0xb3, 0x3f, 0xc1,
+    0xf8, 0x09, 0x89, 0xdc, 0x3b, 0x08, 0xae, 0x85, 0xfa, 0x8e, 0x51, 0xbb,
+    0x6f, 0xf4, 0x73, 0x43, 0xd2, 0xed, 0x6d, 0xfd, 0x2b, 0x23, 0xc3, 0x4f,
+    0xc4, 0x1d, 0x25, 0xb9, 0x36, 0xc4, 0x98, 0xe6, 0xbf, 0xb8, 0x30, 0xcf,
+    0x1b, 0x38, 0x7f, 0xc0, 0x76, 0x67, 0xf8, 0x3f, 0x01, 0x31, 0x3b, 0x87,
+    0x60, 0xf9, 0x90, 0x01, 0x2c, 0x2f, 0xff, 0x6d, 0xfc, 0x8c, 0x3e, 0xeb,
+    0x7f, 0x96, 0x41, 0x82, 0xfd, 0xc6, 0x93, 0x8d, 0xfa, 0x4e, 0x48, 0x49,
+    0x33, 0x3a, 0xa3, 0x5e, 0x61, 0xdf, 0x88, 0x73, 0x66, 0x04, 0xf5, 0xe5,
+    0xd7, 0xea, 0xce, 0x9e, 0xeb, 0xe1, 0x60, 0xb7, 0xf1, 0xcc, 0x0d, 0xc1,
+    0xc4, 0xa0, 0x22, 0x0d, 0xe5, 0x8c, 0x8e, 0x26, 0xf9, 0x89, 0xa5, 0x02,
+    0xf6, 0x4c, 0x3f, 0x10, 0x74, 0x96, 0xe4, 0xdb, 0x12, 0x63, 0x9a, 0xfe,
+    0x70, 0x4e, 0x9a, 0x97, 0xc8, 0xad, 0x5f, 0x39, 0xa0, 0x81, 0x6a, 0xc4,
+    0x93, 0x50, 0x94, 0x1e, 0x17, 0xe3, 0x3f, 0x6d, 0x91, 0x01, 0xed, 0x49,
+    0x96, 0xed, 0x01, 0xc2, 0x2a, 0xe1, 0xc9, 0x39, 0x76, 0x1f, 0x87, 0xb6,
+    0xe3, 0x76, 0xa1, 0xc6, 0x58, 0x1e, 0xdd, 0x2a, 0xdf, 0xbf, 0x82, 0xa3,
+    0x6d, 0x87, 0x72, 0x2c, 0x7c, 0xdc, 0x3f, 0x2b, 0x6a, 0xf1, 0x9a, 0xe0,
+    0x0e, 0xc3, 0xdc, 0x18, 0x3f, 0xc4, 0xbe, 0x11, 0x76, 0x54, 0xab, 0xe3,
+    0xd6, 0x47, 0x90, 0x61, 0x87, 0x66, 0x08, 0x63, 0x95, 0x25, 0x20, 0x43,
+    0x6e, 0x05, 0x80, 0xad, 0x01, 0x10, 0xc7, 0x6c, 0x04, 0xbe, 0xaf, 0xc5,
+    0x50, 0xa7, 0x48, 0x4a, 0x47, 0x44, 0x71, 0xc9, 0xa5, 0xdb, 0xa2, 0x2b,
+    0x12, 0xbc, 0x40, 0x39, 0x31, 0x69, 0x83, 0x03, 0xb9, 0xa0, 0x46, 0xf0,
+    0xb4, 0x4b, 0x1b, 0x8d, 0xda, 0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7e,
+    0xfe, 0x0a, 0x8d, 0xb6, 0x1d, 0xc8, 0xb1, 0xf3, 0x70, 0xfc, 0xad, 0xab,
+    0xc6, 0x6b, 0x80, 0xc8, 0xbb, 0x74, 0x45, 0x62, 0x57, 0x88, 0x07, 0x26,
+    0x2d, 0x30, 0x60, 0x77, 0x34, 0x08, 0xde, 0x16, 0x89, 0x63, 0x71, 0xbb,
+    0x50, 0xe3, 0x2c, 0x0f, 0x6e, 0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52,
+    0x53, 0x83, 0x53, 0xf6, 0x9e, 0x15, 0xb5, 0x78, 0xcd, 0x70, 0x19, 0x17,
+    0x6e, 0x88, 0xac, 0x4a, 0xf1, 0x00, 0xe4, 0xc5, 0xa6, 0x0c, 0x0e, 0xe6,
+    0x81, 0x1b, 0xc2, 0xd1, 0x2c, 0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed,
+    0xd2, 0xad, 0xfc, 0x15, 0xaa, 0x42, 0xea, 0x4a, 0x70, 0x6a, 0x7e, 0xd3,
+    0xc2, 0xb6, 0xaf, 0x19, 0xae, 0x03, 0x22, 0xed, 0xd1, 0x15, 0x89, 0x5e,
+    0x20, 0x1c, 0x98, 0xb4, 0xc1, 0x81, 0xdc, 0xd0, 0x23, 0x78, 0x5a, 0x25,
+    0x8d, 0xc6, 0xed, 0x43, 0x8c, 0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5,
+    0x48, 0x5d, 0x49, 0x4e, 0x0d, 0x4f, 0xda, 0x78, 0x56, 0xd5, 0xe3, 0x35,
+    0xc0, 0x64, 0x5d, 0xba, 0x22, 0xb1, 0x2b, 0xc4, 0x03, 0x93, 0x16, 0x98,
+    0x30, 0x3b, 0x9a, 0x04, 0x6f, 0x0b, 0x44, 0xb1, 0xb8, 0xdd, 0xa8, 0x71,
+    0x96, 0x07, 0xb7, 0x4a, 0xb7, 0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x29, 0xc1,
+    0xa9, 0xfb, 0x4f, 0x0a, 0xda, 0xbc, 0x66, 0xb8, 0x0c, 0x8b, 0xb7, 0x44,
+    0x56, 0x25, 0x78, 0x80, 0x72, 0x62, 0xd3, 0x06, 0x07, 0x73, 0x40, 0x8d,
+    0xe1, 0x68, 0x96, 0x37, 0x1b, 0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56,
+    0xfe, 0x0a, 0xd5, 0x21, 0x75, 0x25, 0x38, 0x35, 0x3f, 0x69, 0xe1, 0x5b,
+    0x57, 0x8c, 0xd7, 0x01, 0x91, 0x76, 0xe8, 0x8a, 0xc4, 0xaf, 0x10, 0x0e,
+    0x4c, 0x5a, 0x60, 0xc0, 0xee, 0x68, 0x11, 0xbc, 0x2d, 0x12, 0xc6, 0xe3,
+    0x76, 0xa1, 0xc6, 0x58, 0x1e, 0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e,
+    0xa4, 0xa7, 0x06, 0xa7, 0xed, 0x3c, 0x2b, 0x6a, 0xf1, 0x9a, 0xe0, 0x32,
+    0x2e, 0xdd, 0x11, 0x58, 0x95, 0xe2, 0x01, 0xc9, 0x8b, 0x4c, 0x18, 0x1d,
+    0xcd, 0x02, 0x37, 0x85, 0xa2, 0x58, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03,
+    0xdb, 0xa5, 0x5b, 0xf8, 0x2b, 0x54, 0x85, 0xd4, 0x94, 0xe0, 0xd4, 0xfd,
+    0xa7, 0x85, 0x6d, 0x5e, 0x33, 0x5c, 0x06, 0x45, 0xdb, 0xa2, 0x2b, 0x12,
+    0xbc, 0x40, 0x39, 0x31, 0x69, 0x83, 0x03, 0xb9, 0xa0, 0x46, 0xf0, 0xb4,
+    0x4b, 0x1b, 0x8d, 0xda, 0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05,
+    0x6a, 0x90, 0xba, 0x92, 0x6a, 0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45,
+    0xee, 0xc5, 0xfd, 0xe1, 0xb0, 0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47,
+    0x09, 0x7b, 0x5c, 0x67, 0x66, 0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50,
+    0xe3, 0x2c, 0x0f, 0x6e, 0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d,
+    0x50, 0x6d, 0x07, 0xa4, 0xfa, 0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36,
+    0x0c, 0x1f, 0xe2, 0x5f, 0x08, 0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec,
+    0xc6, 0xc1, 0xf8, 0x7b, 0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2,
+    0xad, 0xfc, 0x15, 0xaa, 0x42, 0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f,
+    0x4d, 0x0d, 0x17, 0xbb, 0x17, 0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1,
+    0x17, 0x65, 0x1c, 0x25, 0xed, 0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d,
+    0xc6, 0xed, 0x43, 0x8c, 0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48,
+    0x5d, 0x49, 0x35, 0x41, 0xb4, 0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62,
+    0xfe, 0xf0, 0xd8, 0x30, 0x7f, 0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd,
+    0xae, 0x33, 0xb3, 0x1b, 0x07, 0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96,
+    0x07, 0xb7, 0x4a, 0xb7, 0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36,
+    0x83, 0xd2, 0x7d, 0x34, 0x34, 0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f,
+    0xf1, 0x2f, 0x84, 0x5d, 0x94, 0x70, 0x97, 0xb5, 0xc6, 0x76, 0x63, 0x60,
+    0xfc, 0x3d, 0xb7, 0x1b, 0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56, 0xfe,
+    0x0a, 0xd5, 0x21, 0x75, 0x24, 0xd5, 0x06, 0xd0, 0x7a, 0x4f, 0xa6, 0x86,
+    0x8b, 0xdd, 0x8b, 0xfb, 0xc3, 0x60, 0xc1, 0xfe, 0x25, 0xf0, 0x8b, 0xb2,
+    0x8e, 0x12, 0xf6, 0xb8, 0xce, 0xcc, 0x6c, 0x1f, 0x87, 0xb6, 0xe3, 0x76,
+    0xa1, 0xc6, 0x58, 0x1e, 0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e, 0xa4,
+    0x9a, 0xa0, 0xda, 0x0f, 0x49, 0xf4, 0xd0, 0xd1, 0x7b, 0xb1, 0x7f, 0x78,
+    0x6c, 0x18, 0x3f, 0xc4, 0xbe, 0x11, 0x76, 0x51, 0xc2, 0x5e, 0xd7, 0x19,
+    0xd9, 0x8d, 0x83, 0xf0, 0xf6, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03, 0xdb,
+    0xa5, 0x5b, 0xf8, 0x2b, 0x54, 0x85, 0xd4, 0x93, 0x54, 0x1b, 0x41, 0xe9,
+    0x3e, 0x9a, 0x1a, 0x2f, 0x76, 0x2f, 0xef, 0x0d, 0x83, 0x07, 0xf8, 0x97,
+    0xc2, 0x2e, 0xca, 0x38, 0x4b, 0xda, 0xe3, 0x3b, 0x31, 0xb0, 0x7e, 0x1e,
+    0xdb, 0x8d, 0xda, 0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05, 0x6a,
+    0x90, 0xba, 0x92, 0x6a, 0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45, 0xee,
+    0xc5, 0xfd, 0xe1, 0xb0, 0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47, 0x09,
+    0x7b, 0x5c, 0x67, 0x66, 0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50, 0xe3,
+    0x2c, 0x0f, 0x6e, 0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d, 0x50,
+    0x6d, 0x07, 0xa4, 0xfa, 0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36, 0x0c,
+    0x1f, 0xe2, 0x5f, 0x08, 0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec, 0xc6,
+    0xc1, 0xf8, 0x7b, 0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2, 0xad,
+    0xfc, 0x15, 0xaa, 0x42, 0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f, 0x4d,
+    0x0d, 0x17, 0xbb, 0x17, 0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1, 0x17,
+    0x65, 0x1c, 0x25, 0xed, 0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d, 0xc6,
+    0xed, 0x43, 0x8c, 0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48, 0x5d,
+    0x49, 0x35, 0x41, 0xb4, 0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62, 0xfe,
+    0xf0, 0xd8, 0x30, 0x7f, 0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd, 0xae,
+    0x33, 0xb3, 0x1b, 0x07, 0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96, 0x07,
+    0xb7, 0x4a, 0xb7, 0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36, 0x83,
+    0xd2, 0x7d, 0x34, 0x34, 0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f, 0xf1,
+    0x2f, 0x84, 0x5d, 0x94, 0x70, 0x97, 0xb5, 0xc6, 0x76, 0x63, 0x60, 0xfc,
+    0x3d, 0xb7, 0x1b, 0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56, 0xfe, 0x0a,
+    0xd5, 0x21, 0x75, 0x24, 0xd5, 0x06, 0xd0, 0x7a, 0x4f, 0xa6, 0x86, 0x8b,
+    0xdd, 0x8b, 0xfb, 0xc3, 0x60, 0xc1, 0xfe, 0x25, 0xf0, 0x8b, 0xb2, 0x8e,
+    0x12, 0xf6, 0xb8, 0xce, 0xcc, 0x6c, 0x1f, 0x87, 0xb6, 0xe3, 0x76, 0xa1,
+    0xc6, 0x58, 0x1e, 0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e, 0xa4, 0x9a,
+    0xa0, 0xda, 0x0f, 0x49, 0xf4, 0xd0, 0xd1, 0x7b, 0xb1, 0x7f, 0x78, 0x6c,
+    0x18, 0x3f, 0xc4, 0xbe, 0x11, 0x76, 0x51, 0xc2, 0x5e, 0xd7, 0x19, 0xd9,
+    0x8d, 0x83, 0xf0, 0xf6, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03, 0xdb, 0xa5,
+    0x5b, 0xf8, 0x2b, 0x54, 0x85, 0xd4, 0x93, 0x54, 0x1b, 0x41, 0xe9, 0x3e,
+    0x9a, 0x1a, 0x2f, 0x76, 0x2f, 0xef, 0x0d, 0x83, 0x07, 0xf8, 0x97, 0xc2,
+    0x2e, 0xca, 0x38, 0x4b, 0xda, 0xe3, 0x3b, 0x31, 0xb0, 0x7e, 0x1e, 0xdb,
+    0x8d, 0xda, 0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05, 0x6a, 0x90,
+    0xba, 0x92, 0x6a, 0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45, 0xee, 0xc5,
+    0xfd, 0xe1, 0xb0, 0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47, 0x09, 0x7b,
+    0x5c, 0x67, 0x66, 0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50, 0xe3, 0x2c,
+    0x0f, 0x6e, 0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d, 0x50, 0x6d,
+    0x07, 0xa4, 0xfa, 0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36, 0x0c, 0x1f,
+    0xe2, 0x5f, 0x08, 0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec, 0xc6, 0xc1,
+    0xf8, 0x7b, 0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2, 0xad, 0xfc,
+    0x15, 0xaa, 0x42, 0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f, 0x4d, 0x0d,
+    0x17, 0xbb, 0x17, 0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1, 0x17, 0x65,
+    0x1c, 0x25, 0xed, 0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d, 0xc6, 0xed,
+    0x43, 0x8c, 0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48, 0x5d, 0x49,
+    0x35, 0x41, 0xb4, 0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62, 0xfe, 0xf0,
+    0xd8, 0x30, 0x7f, 0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd, 0xae, 0x33,
+    0xb3, 0x1b, 0x07, 0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96, 0x07, 0xb7,
+    0x4a, 0xb7, 0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36, 0x83, 0xd2,
+    0x7d, 0x34, 0x34, 0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f, 0xf1, 0x2f,
+    0x84, 0x5d, 0x94, 0x70, 0x97, 0xb5, 0xc6, 0x76, 0x63, 0x60, 0xfc, 0x3d,
+    0xb7, 0x1b, 0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56, 0xfe, 0x0a, 0xd5,
+    0x21, 0x75, 0x24, 0xd5, 0x06, 0xd0, 0x7a, 0x4f, 0xa6, 0x86, 0x8b, 0xdd,
+    0x8b, 0xfb, 0xc3, 0x60, 0xc1, 0xfe, 0x25, 0xf0, 0x8b, 0xb2, 0x8e, 0x12,
+    0xf6, 0xb8, 0xce, 0xcc, 0x6c, 0x1f, 0x87, 0xb6, 0xe3, 0x76, 0xa1, 0xc6,
+    0x58, 0x1e, 0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e, 0xa4, 0x9a, 0xa0,
+    0xda, 0x0f, 0x49, 0xf4, 0xd0, 0xd1, 0x7b, 0xb1, 0x7f, 0x78, 0x6c, 0x18,
+    0x3f, 0xc4, 0xbe, 0x11, 0x76, 0x51, 0xc2, 0x5e, 0xd7, 0x19, 0xd9, 0x8d,
+    0x83, 0xf0, 0xf6, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03, 0xdb, 0xa5, 0x5b,
+    0xf8, 0x2b, 0x54, 0x85, 0xd4, 0x93, 0x54, 0x1b, 0x41, 0xe9, 0x3e, 0x9a,
+    0x1a, 0x2f, 0x76, 0x2f, 0xef, 0x0d, 0x83, 0x07, 0xf8, 0x97, 0xc2, 0x2e,
+    0xca, 0x38, 0x4b, 0xda, 0xe3, 0x3b, 0x31, 0xb0, 0x7e, 0x1e, 0xdb, 0x8d,
+    0xda, 0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05, 0x6a, 0x90, 0xba,
+    0x92, 0x6a, 0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45, 0xee, 0xc5, 0xfd,
+    0xe1, 0xb0, 0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47, 0x09, 0x7b, 0x5c,
+    0x67, 0x66, 0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50, 0xe3, 0x2c, 0x0f,
+    0x6e, 0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d, 0x50, 0x6d, 0x07,
+    0xa4, 0xfa, 0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36, 0x0c, 0x1f, 0xe2,
+    0x5f, 0x08, 0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec, 0xc6, 0xc1, 0xf8,
+    0x7b, 0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2, 0xad, 0xfc, 0x15,
+    0xaa, 0x42, 0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f, 0x4d, 0x0d, 0x17,
+    0xbb, 0x17, 0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1, 0x17, 0x65, 0x1c,
+    0x25, 0xed, 0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d, 0xc6, 0xed, 0x43,
+    0x8c, 0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48, 0x5d, 0x49, 0x35,
+    0x41, 0xb4, 0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62, 0xfe, 0xf0, 0xd8,
+    0x30, 0x7f, 0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd, 0xae, 0x33, 0xb3,
+    0x1b, 0x07, 0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96, 0x07, 0xb7, 0x4a,
+    0xb7, 0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36, 0x83, 0xd2, 0x7d,
+    0x34, 0x34, 0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f, 0xf1, 0x2f, 0x84,
+    0x5d, 0x94, 0x70, 0x97, 0xb5, 0xc6, 0x76, 0x63, 0x60, 0xfc, 0x3d, 0xb7,
+    0x1b, 0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56, 0xfe, 0x0a, 0xd5, 0x21,
+    0x75, 0x24, 0xd5, 0x06, 0xd0, 0x7a, 0x4f, 0xa6, 0x86, 0x8b, 0xdd, 0x8b,
+    0xfb, 0xc3, 0x60, 0xc1, 0xfe, 0x25, 0xf0, 0x8b, 0xb2, 0x8e, 0x12, 0xf6,
+    0xb8, 0xce, 0xcc, 0x6c, 0x1f, 0x87, 0xb6, 0xe3, 0x76, 0xa1, 0xc6, 0x58,
+    0x1e, 0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e, 0xa4, 0x9a, 0xa0, 0xda,
+    0x0f, 0x49, 0xf4, 0xd0, 0xd1, 0x7b, 0xb1, 0x7f, 0x78, 0x6c, 0x18, 0x3f,
+    0xc4, 0xbe, 0x11, 0x76, 0x51, 0xc2, 0x5e, 0xd7, 0x19, 0xd9, 0x8d, 0x83,
+    0xf0, 0xf6, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03, 0xdb, 0xa5, 0x5b, 0xf8,
+    0x2b, 0x54, 0x85, 0xd4, 0x93, 0x54, 0x1b, 0x41, 0xe9, 0x3e, 0x9a, 0x1a,
+    0x2f, 0x76, 0x2f, 0xef, 0x0d, 0x83, 0x07, 0xf8, 0x97, 0xc2, 0x2e, 0xca,
+    0x38, 0x4b, 0xda, 0xe3, 0x3b, 0x31, 0xb0, 0x7e, 0x1e, 0xdb, 0x8d, 0xda,
+    0x87, 0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05, 0x6a, 0x90, 0xba, 0x92,
+    0x6a, 0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45, 0xee, 0xc5, 0xfd, 0xe1,
+    0xb0, 0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47, 0x09, 0x7b, 0x5c, 0x67,
+    0x66, 0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50, 0xe3, 0x2c, 0x0f, 0x6e,
+    0x95, 0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d, 0x50, 0x6d, 0x07, 0xa4,
+    0xfa, 0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36, 0x0c, 0x1f, 0xe2, 0x5f,
+    0x08, 0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec, 0xc6, 0xc1, 0xf8, 0x7b,
+    0x6e, 0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2, 0xad, 0xfc, 0x15, 0xaa,
+    0x42, 0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f, 0x4d, 0x0d, 0x17, 0xbb,
+    0x17, 0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1, 0x17, 0x65, 0x1c, 0x25,
+    0xed, 0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d, 0xc6, 0xed, 0x43, 0x8c,
+    0xb0, 0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48, 0x5d, 0x49, 0x35, 0x41,
+    0xb4, 0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62, 0xfe, 0xf0, 0xd8, 0x30,
+    0x7f, 0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd, 0xae, 0x33, 0xb3, 0x1b,
+    0x07, 0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96, 0x07, 0xb7, 0x4a, 0xb7,
+    0xf0, 0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36, 0x83, 0xd2, 0x7d, 0x34,
+    0x34, 0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f, 0xf1, 0x2f, 0x84, 0x5d,
+    0x94, 0x70, 0x97, 0xb5, 0xc6, 0x76, 0x63, 0x60, 0xfc, 0x3d, 0xb7, 0x1b,
+    0xb5, 0x0e, 0x32, 0xc0, 0xf6, 0xe9, 0x56, 0xfe, 0x0a, 0xd5, 0x21, 0x75,
+    0x24, 0xd5, 0x06, 0xd0, 0x7a, 0x4f, 0xa6, 0x86, 0x8b, 0xdd, 0x8b, 0xfb,
+    0xc3, 0x60, 0xc1, 0xfe, 0x25, 0xf0, 0x8b, 0xb2, 0x8e, 0x12, 0xf6, 0xb8,
+    0xce, 0xcc, 0x6c, 0x1f, 0x87, 0xb6, 0xe3, 0x76, 0xa1, 0xc6, 0x58, 0x1e,
+    0xdd, 0x2a, 0xdf, 0xc1, 0x5a, 0xa4, 0x2e, 0xa4, 0x9a, 0xa0, 0xda, 0x0f,
+    0x49, 0xf4, 0xd0, 0xd1, 0x7b, 0xb1, 0x7f, 0x78, 0x6c, 0x18, 0x3f, 0xc4,
+    0xbe, 0x11, 0x76, 0x51, 0xc2, 0x5e, 0xd7, 0x19, 0xd9, 0x8d, 0x83, 0xf0,
+    0xf6, 0xdc, 0x6e, 0xd4, 0x38, 0xcb, 0x03, 0xdb, 0xa5, 0x5b, 0xf8, 0x2b,
+    0x54, 0x85, 0xd4, 0x93, 0x54, 0x1b, 0x41, 0xe9, 0x3e, 0x9a, 0x1a, 0x2f,
+    0x76, 0x2f, 0xef, 0x0d, 0x83, 0x07, 0xf8, 0x97, 0xc2, 0x2e, 0xca, 0x38,
+    0x4b, 0xda, 0xe3, 0x3b, 0x31, 0xb0, 0x7e, 0x1e, 0xdb, 0x8d, 0xda, 0x87,
+    0x19, 0x60, 0x7b, 0x74, 0xab, 0x7f, 0x05, 0x6a, 0x90, 0xba, 0x92, 0x6a,
+    0x83, 0x68, 0x3d, 0x27, 0xd3, 0x43, 0x45, 0xee, 0xc5, 0xfd, 0xe1, 0xb0,
+    0x60, 0xff, 0x12, 0xf8, 0x45, 0xd9, 0x47, 0x09, 0x7b, 0x5c, 0x67, 0x66,
+    0x36, 0x0f, 0xc3, 0xdb, 0x71, 0xbb, 0x50, 0xe3, 0x2c, 0x0f, 0x6e, 0x95,
+    0x6f, 0xe0, 0xad, 0x52, 0x17, 0x52, 0x4d, 0x50, 0x6d, 0x07, 0xa4, 0xfa,
+    0x68, 0x68, 0xbd, 0xd8, 0xbf, 0xbc, 0x36, 0x0c, 0x1f, 0xe2, 0x5f, 0x08,
+    0xbb, 0x28, 0xe1, 0x2f, 0x6b, 0x8c, 0xec, 0xc6, 0xc1, 0xf8, 0x7b, 0x6e,
+    0x37, 0x6a, 0x1c, 0x65, 0x81, 0xed, 0xd2, 0xad, 0xfc, 0x15, 0xaa, 0x42,
+    0xea, 0x49, 0xaa, 0x0d, 0xa0, 0xf4, 0x9f, 0x4d, 0x0d, 0x17, 0xbb, 0x17,
+    0xf7, 0x86, 0xc1, 0x83, 0xfc, 0x4b, 0xe1, 0x17, 0x65, 0x1c, 0x25, 0xed,
+    0x71, 0x9d, 0x98, 0xd8, 0x3f, 0x0f, 0x6d, 0xc6, 0xed, 0x43, 0x8c, 0xb0,
+    0x3d, 0xba, 0x55, 0xbf, 0x82, 0xb5, 0x48, 0x5d, 0x49, 0x35, 0x41, 0xb4,
+    0x1e, 0x93, 0xe9, 0xa1, 0xa2, 0xf7, 0x62, 0xfe, 0xf0, 0xd8, 0x30, 0x7f,
+    0x89, 0x7c, 0x22, 0xec, 0xa3, 0x84, 0xbd, 0xae, 0x33, 0xb3, 0x1b, 0x07,
+    0xe1, 0xed, 0xb8, 0xdd, 0xa8, 0x71, 0x96, 0x07, 0xb7, 0x4a, 0xb7, 0xf0,
+    0x56, 0xa9, 0x0b, 0xa9, 0x26, 0xa8, 0x36, 0x83, 0xd2, 0x7d, 0x34, 0x34,
+    0x5e, 0xec, 0x5f, 0xde, 0x1b, 0x06, 0x0f, 0xf1, 0x2f, 0x84, 0x5d, 0x94,
+    0x70, 0x97, 0xb5, 0xc6, 0x7c,
+};
+static_assert(sizeof(kBytesTestReadSymbol12) == kNumBytesTestReadSymbol12, "");
+
+// The kBytesTestReadSymbol13[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][14] = {
+//   // pmf: 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13, 1/13,
+//   // 1/13, 1/13
+//   { 32768 - 2521, 32768 - 5041, 32768 - 7562, 32768 - 10082, 32768 - 12603,
+//     32768 - 15124, 32768 - 17644, 32768 - 20165, 32768 - 22686,
+//     32768 - 25206, 32768 - 27727, 32768 - 30247, 0, 0 },
+//   // pmf: 3/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26,
+//   // 2/26, 1/26
+//   { 32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343, 32768 - 13863,
+//     32768 - 16384, 32768 - 18905, 32768 - 21425, 32768 - 23946,
+//     32768 - 26466, 32768 - 28987, 32768 - 31508, 0, 0 },
+//   // pmf: 1/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26, 2/26,
+//   // 2/26, 3/26
+//   { 32768 - 1260, 32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343,
+//     32768 - 13863, 32768 - 16384, 32768 - 18905, 32768 - 21425,
+//     32768 - 23946, 32768 - 26466, 32768 - 28987, 0, 0 },
+//   // pmf: 1/26, 2/26, 2/26, 2/26, 2/26, 2/26, 4/26, 2/26, 2/26, 2/26, 2/26,
+//   // 2/26, 1/26
+//   { 32768 - 1260, 32768 - 3781, 32768 - 6302, 32768 - 8822, 32768 - 11343,
+//     32768 - 13863, 32768 - 18905, 32768 - 21425, 32768 - 23946,
+//     32768 - 26466, 32768 - 28987, 32768 - 31508, 0, 0 },
+// };
+// constexpr int kSymbols[26][4] = { { 0, 6, 12, 5 },     //
+//                                   { 1, 7, 11, 4 },     //
+//                                   { 2, 8, 10, 3 },     //
+//                                   { 3, 9, 9, 2 },      //
+//                                   { 4, 10, 8, 1 },     //
+//                                   { 5, 11, 7, 0 },     //
+//                                   { 6, 12, 6, 12 },    //
+//                                   { 7, 0, 5, 11 },     //
+//                                   { 8, 1, 4, 10 },     //
+//                                   { 9, 2, 3, 9 },      //
+//                                   { 10, 3, 2, 8 },     //
+//                                   { 11, 4, 1, 7 },     //
+//                                   { 12, 5, 0, 6 },     //
+//                                   { 0, 0, 12, 11 },    //
+//                                   { 2, 1, 10, 9 },     //
+//                                   { 4, 3, 8, 7 },      //
+//                                   { 6, 5, 6, 5 },      //
+//                                   { 8, 7, 4, 3 },      //
+//                                   { 10, 9, 2, 1 },     //
+//                                   { 12, 11, 12, 10 },  //
+//                                   { 1, 0, 11, 8 },     //
+//                                   { 3, 2, 9, 6 },      //
+//                                   { 5, 4, 7, 4 },      //
+//                                   { 7, 6, 5, 2 },      //
+//                                   { 9, 8, 3, 6 },      //
+//                                   { 11, 10, 1, 6 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 64; ++i) {
+//   for (int j = 0; j < 26; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 13);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol13 = 3110;
+constexpr uint8_t kBytesTestReadSymbol13[] = {
+    0x0b, 0x38, 0xa7, 0x3e, 0xde, 0x47, 0x2e, 0xe6, 0x9e, 0xe0, 0xa8, 0xc4,
+    0x77, 0xda, 0x41, 0x64, 0x49, 0x60, 0xc4, 0x26, 0x68, 0xac, 0xf4, 0xa6,
+    0x8c, 0x6e, 0xa6, 0xd3, 0xd9, 0x4b, 0xb9, 0x35, 0xb6, 0x53, 0x6c, 0x73,
+    0x13, 0xd7, 0xfb, 0xbf, 0x96, 0xac, 0xea, 0x86, 0xb5, 0x24, 0x14, 0x2a,
+    0x5a, 0x41, 0x38, 0xab, 0xfb, 0x92, 0x74, 0xf4, 0x0f, 0x24, 0xde, 0x2d,
+    0x2d, 0x12, 0xd7, 0xb8, 0x2f, 0x4a, 0x4c, 0xd6, 0xc0, 0x4b, 0x01, 0x98,
+    0xca, 0x7e, 0xde, 0x03, 0x75, 0x27, 0x59, 0x4f, 0x32, 0x54, 0xa5, 0xb5,
+    0x79, 0xc3, 0xc4, 0x3c, 0x76, 0xa3, 0x2f, 0xaf, 0x2f, 0x0a, 0x84, 0xb5,
+    0x60, 0xf5, 0x73, 0x88, 0xc0, 0x24, 0x1c, 0xfb, 0xff, 0x90, 0xb6, 0x05,
+    0xe9, 0x43, 0x90, 0xc8, 0xd3, 0xfd, 0x3f, 0xc2, 0x0b, 0xb5, 0xfe, 0x12,
+    0x55, 0x23, 0xa1, 0xf4, 0xba, 0xc7, 0x1f, 0xc3, 0xe5, 0xe3, 0x76, 0x68,
+    0x3c, 0x57, 0xb9, 0x92, 0xea, 0x25, 0x93, 0x4e, 0x72, 0xff, 0x63, 0x28,
+    0x0c, 0x90, 0x1d, 0xb6, 0x42, 0xb2, 0x25, 0x79, 0x8e, 0xee, 0x0c, 0x56,
+    0x3d, 0x94, 0x3d, 0x80, 0xf2, 0x25, 0x6f, 0xd4, 0x93, 0x31, 0x18, 0x80,
+    0x5a, 0x3a, 0xbb, 0x4d, 0xbb, 0x77, 0xc3, 0xb0, 0x20, 0x0e, 0xd3, 0xd8,
+    0x10, 0x05, 0xb2, 0x81, 0x57, 0xf5, 0x8c, 0xe5, 0xac, 0x46, 0xc0, 0xae,
+    0x9c, 0x08, 0x9d, 0x51, 0xf3, 0x16, 0xb9, 0xd7, 0x90, 0xa7, 0x9f, 0x40,
+    0x5d, 0x14, 0xd1, 0xbd, 0xa2, 0x0b, 0xf3, 0xae, 0x3b, 0xfb, 0x0f, 0xe1,
+    0x1a, 0x6e, 0x63, 0x3b, 0xdb, 0x41, 0x8e, 0xe8, 0x1f, 0x20, 0x18, 0xbe,
+    0x69, 0x10, 0x86, 0x06, 0x06, 0x23, 0x3a, 0x40, 0xc1, 0x7f, 0x2e, 0x32,
+    0xb4, 0x23, 0xac, 0x4b, 0x25, 0x6b, 0xef, 0xaf, 0xec, 0x5c, 0xf2, 0xd0,
+    0x61, 0xb2, 0x3a, 0xa5, 0x3d, 0xcd, 0xf7, 0x99, 0x6b, 0x4e, 0xbb, 0x58,
+    0x6a, 0x4c, 0xd7, 0xc0, 0x77, 0xd9, 0xae, 0x15, 0x7e, 0xde, 0xc9, 0xd8,
+    0x24, 0x39, 0x3f, 0xa4, 0xf3, 0x24, 0x7e, 0xe0, 0x22, 0x19, 0x40, 0x3d,
+    0x0c, 0xb0, 0xb7, 0xe3, 0x4b, 0x82, 0x6f, 0x82, 0x0e, 0xb1, 0x91, 0xef,
+    0x84, 0x98, 0x69, 0x66, 0x24, 0xe7, 0x90, 0x13, 0x0d, 0xbd, 0x6b, 0x92,
+    0xee, 0x1c, 0x0f, 0xe7, 0xfa, 0xb9, 0xb4, 0x6c, 0x68, 0x98, 0x4c, 0x27,
+    0x42, 0xad, 0x5f, 0x8f, 0xe5, 0x25, 0xf9, 0x67, 0x84, 0x86, 0x2e, 0xf6,
+    0x51, 0x71, 0x0d, 0x6c, 0x45, 0x8f, 0x96, 0x15, 0x73, 0xab, 0xff, 0xc0,
+    0x87, 0x14, 0xba, 0x00, 0x67, 0x2c, 0x27, 0x03, 0xff, 0xa6, 0xe3, 0x09,
+    0xae, 0xbb, 0xa5, 0x49, 0xee, 0x5f, 0x47, 0xc0, 0x30, 0x4a, 0x93, 0x28,
+    0x48, 0x4d, 0x30, 0x49, 0xe7, 0xe6, 0x79, 0x96, 0x75, 0x6c, 0x62, 0xbc,
+    0x9f, 0xaa, 0x39, 0x63, 0x1d, 0x33, 0xce, 0xd2, 0xa3, 0xd1, 0x93, 0xed,
+    0x8d, 0xa6, 0xbd, 0x02, 0xf0, 0x44, 0xd5, 0x9e, 0x29, 0x02, 0x46, 0x87,
+    0xaf, 0xdb, 0xfb, 0x20, 0x29, 0x26, 0xb7, 0x8c, 0x75, 0xee, 0xe9, 0x29,
+    0x53, 0x01, 0x4a, 0xaa, 0xc2, 0x9f, 0x6c, 0x30, 0x21, 0x83, 0xa6, 0x09,
+    0x32, 0x1d, 0xaa, 0x00, 0x6c, 0xea, 0x9c, 0x84, 0x16, 0x16, 0x0c, 0x06,
+    0xcc, 0xf0, 0x19, 0xce, 0x57, 0xb3, 0x9f, 0x57, 0xf0, 0xdc, 0xda, 0x86,
+    0x85, 0x2f, 0x09, 0x33, 0x8d, 0x59, 0xb8, 0xc1, 0x08, 0x4c, 0xee, 0xf8,
+    0x33, 0x3d, 0x23, 0x13, 0x78, 0xa3, 0x98, 0xbf, 0xab, 0xef, 0x15, 0xe2,
+    0x8d, 0xdb, 0xb4, 0xd0, 0x4b, 0x2f, 0x04, 0x3f, 0x6b, 0x11, 0xf0, 0x05,
+    0xc7, 0x53, 0x1e, 0xc9, 0x73, 0x11, 0x81, 0xd3, 0xde, 0x21, 0xd8, 0x14,
+    0x10, 0xbe, 0x30, 0xb2, 0x48, 0x55, 0x9b, 0x8c, 0x10, 0x84, 0xce, 0xef,
+    0x83, 0x2f, 0x03, 0x10, 0x09, 0x0f, 0x70, 0xa8, 0x84, 0xea, 0x15, 0xdb,
+    0xc7, 0xdf, 0x6f, 0x67, 0x5d, 0x1c, 0xc7, 0x1a, 0x1c, 0x15, 0xa6, 0x92,
+    0xed, 0x63, 0xf0, 0xed, 0x77, 0x5d, 0x12, 0x1b, 0x8c, 0xab, 0x3e, 0xfa,
+    0x12, 0xf6, 0x83, 0xda, 0x41, 0xbc, 0x97, 0x76, 0xb9, 0x1f, 0xc9, 0x36,
+    0xc7, 0xe3, 0x9f, 0x93, 0x2e, 0x27, 0xdc, 0x90, 0x84, 0x6d, 0x81, 0x04,
+    0x09, 0x4f, 0x10, 0xb9, 0x53, 0xd9, 0x8f, 0x99, 0x2b, 0x8b, 0x53, 0x4f,
+    0xe8, 0x3e, 0x82, 0x1b, 0x0c, 0x3d, 0xbc, 0xe5, 0x5c, 0x13, 0xed, 0x4b,
+    0x0b, 0x05, 0x72, 0xaa, 0xd2, 0xcf, 0xfc, 0x9f, 0xd0, 0xfd, 0xc7, 0xc6,
+    0xc0, 0xa3, 0xa7, 0x05, 0xbb, 0x9e, 0xae, 0x63, 0xc0, 0x3d, 0x73, 0x92,
+    0xe1, 0x98, 0xe4, 0xa5, 0xb3, 0xc4, 0x36, 0x90, 0x35, 0x6b, 0xab, 0x35,
+    0x06, 0x98, 0xca, 0x35, 0x20, 0x5a, 0x6a, 0x84, 0x5c, 0x88, 0xca, 0x64,
+    0x43, 0x87, 0xf2, 0x3c, 0x13, 0x58, 0x1c, 0x35, 0x2c, 0xf2, 0x1d, 0x5e,
+    0xe0, 0x1b, 0x2c, 0x59, 0xc2, 0xcd, 0xf2, 0x96, 0x1a, 0x75, 0x3c, 0x10,
+    0xe7, 0xe3, 0xa1, 0xbc, 0xec, 0x03, 0x79, 0x58, 0x26, 0x4d, 0xcf, 0xb4,
+    0x00, 0xd3, 0x46, 0xee, 0x99, 0x52, 0x2f, 0x54, 0xcb, 0xa1, 0x75, 0xa1,
+    0xa0, 0xf4, 0xaa, 0xe9, 0x4a, 0xe1, 0x74, 0xcc, 0xd1, 0x47, 0xda, 0x48,
+    0x8b, 0x2e, 0xf9, 0x54, 0x98, 0x4e, 0x4f, 0x5a, 0x1b, 0xf5, 0x66, 0x62,
+    0xa0, 0xc2, 0x0e, 0x1a, 0x91, 0xbd, 0x7a, 0x33, 0xfd, 0x7c, 0xfc, 0x8b,
+    0xc0, 0x92, 0xd8, 0x97, 0x48, 0x6f, 0xf4, 0xe0, 0x6c, 0xcf, 0x17, 0xc9,
+    0x44, 0x04, 0xcf, 0x50, 0x0d, 0x8f, 0xbc, 0x4f, 0x4e, 0x1d, 0x38, 0x38,
+    0x5c, 0xb7, 0x8e, 0xe7, 0x52, 0xbe, 0x04, 0x68, 0x79, 0x9e, 0x68, 0x32,
+    0x3b, 0xe4, 0xee, 0x65, 0x76, 0xf6, 0xb4, 0x47, 0x1c, 0xa5, 0xd0, 0x20,
+    0x0f, 0x94, 0xe1, 0x2f, 0xa8, 0x87, 0xeb, 0xda, 0x2c, 0x54, 0xc4, 0x07,
+    0x08, 0x89, 0xdc, 0xcf, 0x73, 0x0c, 0x1f, 0xea, 0xb4, 0x6d, 0xea, 0x17,
+    0x70, 0x82, 0xb5, 0x18, 0x2f, 0x38, 0xc5, 0x47, 0x47, 0xd6, 0x37, 0x20,
+    0x8d, 0x71, 0xd6, 0x16, 0x4d, 0x16, 0xd5, 0x77, 0x36, 0xb5, 0xd0, 0x20,
+    0x5f, 0x4d, 0x89, 0x6c, 0x49, 0xc4, 0x13, 0x6c, 0x26, 0x8c, 0x8f, 0x6f,
+    0x17, 0xab, 0xdf, 0x57, 0xa8, 0xab, 0xed, 0x8d, 0xa9, 0x00, 0x6b, 0xfc,
+    0xf6, 0x72, 0xaf, 0x32, 0xc2, 0x0b, 0xb6, 0x6b, 0x7a, 0xac, 0xa9, 0x77,
+    0x52, 0x87, 0x98, 0x43, 0x21, 0x72, 0x35, 0x6c, 0x27, 0x12, 0xbe, 0xf0,
+    0x62, 0x16, 0x2a, 0xc6, 0xf7, 0x48, 0xd2, 0xc3, 0x25, 0xb4, 0x6a, 0x57,
+    0x65, 0xd6, 0x07, 0xa0, 0xde, 0x9f, 0x3b, 0x3d, 0xdd, 0x27, 0x0e, 0x4c,
+    0xe8, 0x4b, 0xe1, 0xd6, 0x33, 0xa7, 0x85, 0x75, 0x44, 0x7e, 0xf9, 0xfd,
+    0xb9, 0x98, 0xa8, 0x30, 0x82, 0xdf, 0xd9, 0x97, 0x5c, 0x3f, 0x52, 0x20,
+    0xd4, 0x38, 0x88, 0xc1, 0x53, 0x11, 0x14, 0x25, 0x6f, 0xeb, 0x4e, 0xf5,
+    0xed, 0xf4, 0xba, 0x34, 0x23, 0x74, 0xbc, 0x46, 0x51, 0x96, 0x1b, 0x50,
+    0x32, 0x03, 0xe5, 0x6d, 0xd7, 0xcf, 0xca, 0x60, 0xb2, 0xbc, 0xb6, 0x4b,
+    0xc0, 0xee, 0x8b, 0x96, 0xa9, 0x4c, 0x1d, 0x9b, 0x2d, 0x11, 0xc7, 0x29,
+    0x74, 0x08, 0x03, 0xe5, 0x1c, 0xe2, 0x6c, 0x21, 0x1e, 0x02, 0x4d, 0xb1,
+    0x4e, 0x70, 0xb3, 0xfc, 0x06, 0xa5, 0xf9, 0xfb, 0x35, 0x1c, 0x89, 0xe3,
+    0x1e, 0x27, 0xe0, 0x93, 0xd6, 0xd5, 0x15, 0x94, 0x40, 0x88, 0x71, 0xfd,
+    0xaa, 0xbd, 0xf6, 0xae, 0x61, 0x52, 0x49, 0x33, 0x99, 0x85, 0xcd, 0x13,
+    0x70, 0x7e, 0x1b, 0x76, 0x3a, 0x69, 0x9e, 0xfe, 0x3c, 0x65, 0x22, 0xf0,
+    0x1f, 0x91, 0x57, 0x00, 0x5b, 0x28, 0xac, 0x1e, 0x1e, 0x24, 0xc7, 0xd8,
+    0xdb, 0x3a, 0xd0, 0x85, 0x04, 0x4d, 0xf7, 0xe8, 0x3b, 0xdc, 0xa1, 0x5b,
+    0x5e, 0xe3, 0x7a, 0xae, 0x72, 0x70, 0x7c, 0x52, 0x07, 0xf5, 0x1c, 0xda,
+    0xd7, 0x40, 0x81, 0x7d, 0x36, 0x0a, 0x97, 0x8e, 0x0c, 0x25, 0xe7, 0xd3,
+    0x81, 0xb0, 0xe2, 0xd0, 0x56, 0x16, 0x9c, 0x9d, 0x0e, 0xc7, 0x97, 0x8f,
+    0xff, 0x68, 0xd4, 0x4f, 0x1a, 0x4c, 0x58, 0x6f, 0xe4, 0xd5, 0xc1, 0x07,
+    0x7f, 0x31, 0x8c, 0x59, 0x02, 0x6f, 0xa7, 0x54, 0x1b, 0x02, 0x35, 0xe5,
+    0x14, 0xec, 0x35, 0x3d, 0x17, 0x72, 0x11, 0x0c, 0x38, 0x62, 0x99, 0x4a,
+    0x6a, 0x46, 0xcb, 0x36, 0x1b, 0x4b, 0x38, 0xff, 0x1d, 0xa4, 0xf7, 0x21,
+    0xda, 0x73, 0x42, 0xc4, 0x2b, 0xf8, 0xd8, 0x43, 0x73, 0x60, 0x11, 0x22,
+    0xc9, 0xe6, 0x07, 0xca, 0xa0, 0x29, 0x2a, 0x20, 0xd9, 0xdd, 0x7d, 0xed,
+    0x28, 0x10, 0xde, 0xbe, 0x5e, 0xfd, 0x0c, 0x06, 0x4b, 0x1c, 0xc4, 0x56,
+    0xc4, 0x12, 0x25, 0x5a, 0xd1, 0xfe, 0x03, 0x5e, 0x5e, 0xe0, 0x42, 0x8e,
+    0x44, 0xf1, 0x8f, 0x13, 0xf0, 0x49, 0xeb, 0x59, 0xf3, 0x5b, 0x61, 0xd9,
+    0xa4, 0xdf, 0x2e, 0x2a, 0x70, 0xc2, 0xf0, 0xef, 0x16, 0xf4, 0x1b, 0x5c,
+    0xbd, 0x77, 0x42, 0xb9, 0x4c, 0x56, 0x8d, 0xc8, 0xf8, 0x05, 0xbd, 0x52,
+    0xba, 0x6e, 0xe1, 0x89, 0xe1, 0xf2, 0xdb, 0xa7, 0xdf, 0xe0, 0xee, 0xc1,
+    0x5c, 0x9e, 0x90, 0x11, 0x17, 0xd5, 0xc1, 0xb9, 0x2c, 0x08, 0x62, 0x0d,
+    0x75, 0x05, 0xb2, 0xad, 0x22, 0xd6, 0x5c, 0x6e, 0xed, 0xa4, 0x06, 0x5a,
+    0x42, 0x4f, 0xbf, 0x84, 0x53, 0xfa, 0x0b, 0xb7, 0x47, 0x6c, 0xba, 0x07,
+    0xc9, 0xe4, 0x8c, 0xe4, 0xa3, 0x40, 0xdc, 0xcb, 0x58, 0xeb, 0xba, 0xc5,
+    0xcc, 0x56, 0x74, 0x1e, 0x7b, 0x0f, 0x2a, 0xce, 0x35, 0x46, 0x39, 0x6d,
+    0x81, 0x91, 0xb2, 0x05, 0x76, 0xfa, 0x8f, 0x43, 0x46, 0x25, 0xb7, 0x98,
+    0x4e, 0x5f, 0x63, 0xf4, 0x0e, 0x4f, 0x5d, 0x85, 0x29, 0x9d, 0xdb, 0xa8,
+    0xeb, 0x0a, 0xbb, 0xc4, 0xf8, 0x5a, 0xda, 0xe1, 0x9b, 0x1f, 0x9b, 0x4d,
+    0x62, 0x65, 0x41, 0x34, 0x5b, 0x6c, 0x19, 0xa5, 0x3c, 0x35, 0x8e, 0x14,
+    0x02, 0xcd, 0x1d, 0xf3, 0xfb, 0x70, 0x93, 0x46, 0xe2, 0x49, 0xc8, 0x31,
+    0xfd, 0x47, 0x35, 0xfc, 0x7d, 0xb9, 0x79, 0xf7, 0x0d, 0xed, 0x98, 0x47,
+    0xd2, 0xcf, 0x26, 0x8b, 0x10, 0x6f, 0x86, 0xca, 0xda, 0xb8, 0x41, 0xdb,
+    0x0c, 0xc7, 0xc3, 0x56, 0xc5, 0x0f, 0xc7, 0xf2, 0xda, 0x45, 0xdf, 0x94,
+    0xc1, 0x65, 0x79, 0x6c, 0x97, 0x81, 0xbd, 0xf1, 0x1e, 0x26, 0x6e, 0xfc,
+    0x4f, 0x2e, 0x1e, 0x9c, 0xa2, 0x69, 0x54, 0x7a, 0xc3, 0x15, 0x44, 0x64,
+    0x73, 0x11, 0x5b, 0x10, 0x48, 0x95, 0x6b, 0x49, 0x4e, 0xcb, 0x2b, 0x12,
+    0x90, 0xaf, 0xf5, 0x5a, 0xfa, 0xf5, 0x0b, 0xb8, 0x49, 0x0a, 0x7d, 0xc4,
+    0x6b, 0x0a, 0xa5, 0x6d, 0x32, 0xb2, 0x33, 0x3c, 0xb3, 0x65, 0x9c, 0x1f,
+    0x7e, 0x50, 0xd3, 0x6a, 0xa2, 0xc1, 0xb9, 0xd9, 0xfa, 0x25, 0xfe, 0x1c,
+    0x3f, 0x88, 0x47, 0x0a, 0x7e, 0x62, 0xa2, 0xf3, 0x3e, 0xae, 0x9f, 0x7f,
+    0x83, 0xbb, 0x05, 0x72, 0x7a, 0x40, 0x44, 0x5f, 0x57, 0x06, 0xe4, 0xb0,
+    0x21, 0x88, 0x35, 0xd4, 0x16, 0xca, 0xb4, 0x8b, 0x59, 0x71, 0xbb, 0xb6,
+    0x90, 0x19, 0x69, 0x09, 0x3e, 0xfe, 0x11, 0x4f, 0xe8, 0x2e, 0xdd, 0x1d,
+    0xb2, 0xe8, 0x1f, 0x27, 0x92, 0x33, 0x92, 0x8d, 0x04, 0x2e, 0x19, 0x16,
+    0xb4, 0xb5, 0xcf, 0x52, 0x98, 0xcc, 0x2b, 0x85, 0x0c, 0x2d, 0x88, 0x38,
+    0x24, 0x06, 0xf2, 0x47, 0xec, 0xce, 0xc6, 0xf7, 0x4e, 0xe4, 0x8b, 0xb5,
+    0x4f, 0xbe, 0xae, 0x13, 0xd5, 0x0c, 0xe6, 0x13, 0x44, 0xa4, 0x76, 0x19,
+    0x8c, 0x25, 0x28, 0x0f, 0x15, 0x8e, 0xa6, 0x9c, 0xee, 0x6e, 0xf0, 0x55,
+    0x9d, 0x5a, 0x8f, 0xf6, 0x08, 0x27, 0x92, 0x1f, 0xcb, 0x4c, 0x8c, 0x2c,
+    0xeb, 0x44, 0x26, 0x48, 0xec, 0x2e, 0x9b, 0xb3, 0xd9, 0x17, 0xee, 0x52,
+    0x7d, 0x32, 0x47, 0x88, 0x4d, 0xf9, 0x11, 0xfc, 0xac, 0xa3, 0xb0, 0xc9,
+    0x5e, 0x38, 0xa3, 0x8d, 0x56, 0xc8, 0x83, 0x7c, 0x53, 0x38, 0xe1, 0xd0,
+    0x28, 0x7d, 0xc1, 0x65, 0x99, 0x39, 0x58, 0x36, 0xa3, 0x66, 0x71, 0x4c,
+    0x28, 0xcb, 0x9f, 0xb5, 0x58, 0x4b, 0xa3, 0x5c, 0x4e, 0xf9, 0x8d, 0x5b,
+    0x0c, 0xf1, 0x32, 0xbb, 0xe3, 0xb4, 0x47, 0xe8, 0x1c, 0x9e, 0xbb, 0x0a,
+    0x53, 0x3b, 0xb7, 0x51, 0xd6, 0x15, 0x77, 0x89, 0xf0, 0xb5, 0xba, 0x71,
+    0x84, 0x16, 0x81, 0xb0, 0xdf, 0x67, 0x12, 0x9f, 0xe7, 0x43, 0x70, 0x3a,
+    0xb1, 0xdc, 0x40, 0x31, 0xe7, 0xdd, 0x6b, 0x74, 0xfc, 0x18, 0x7d, 0x0d,
+    0xba, 0xda, 0x67, 0x66, 0x56, 0x43, 0x42, 0x80, 0xc6, 0x7c, 0xb3, 0x6c,
+    0x89, 0x2e, 0xc7, 0x0d, 0x97, 0x8a, 0xbe, 0x1a, 0x36, 0x05, 0x10, 0x85,
+    0x96, 0xa8, 0xbd, 0x29, 0x85, 0x52, 0xdc, 0xa3, 0x92, 0x20, 0xa1, 0xb0,
+    0x45, 0x5a, 0x7e, 0xc3, 0x4c, 0x0b, 0x6f, 0x3a, 0xe4, 0xfe, 0x55, 0x01,
+    0x49, 0x51, 0x06, 0xe7, 0xbb, 0x91, 0xd2, 0x77, 0x80, 0x1e, 0x07, 0xc7,
+    0xe8, 0x60, 0x32, 0x58, 0xe6, 0x22, 0xb6, 0x20, 0x91, 0x2a, 0xd6, 0x92,
+    0x9d, 0x96, 0x56, 0x25, 0x21, 0x5f, 0xea, 0xb5, 0xf5, 0xea, 0x17, 0x70,
+    0x92, 0x14, 0xfb, 0x88, 0xd6, 0x15, 0x4a, 0xda, 0x65, 0x64, 0x66, 0x79,
+    0x66, 0xcb, 0x38, 0x3e, 0xfc, 0xa1, 0xa0, 0x96, 0xf7, 0xb0, 0x4d, 0x87,
+    0x80, 0x05, 0x1e, 0x85, 0xd8, 0xb8, 0xf8, 0x50, 0x3e, 0x9d, 0xc1, 0x83,
+    0x81, 0x15, 0x59, 0x5d, 0x49, 0xd0, 0xed, 0x25, 0x2a, 0xf3, 0x59, 0xe4,
+    0xc6, 0x4b, 0xc2, 0x0f, 0x19, 0x92, 0x2f, 0x7f, 0x96, 0xd0, 0x90, 0x08,
+    0xef, 0x4f, 0x57, 0xa5, 0x3e, 0xec, 0xbe, 0xa5, 0x31, 0xd5, 0xcb, 0xbb,
+    0xab, 0xde, 0x3b, 0xc8, 0x62, 0x8e, 0x35, 0x5b, 0x22, 0x0d, 0xf1, 0x4c,
+    0xe3, 0x87, 0x40, 0xa1, 0xf7, 0x05, 0x96, 0x64, 0xe5, 0x60, 0xda, 0x8d,
+    0x99, 0xc5, 0x30, 0xa3, 0x2e, 0x7e, 0xd5, 0x61, 0x2e, 0x8d, 0x71, 0x3b,
+    0xe6, 0x35, 0x6c, 0x33, 0xc4, 0xca, 0xef, 0x8e, 0xd1, 0x1f, 0xa0, 0x72,
+    0x7a, 0xec, 0x29, 0x4c, 0xee, 0xdd, 0x47, 0x58, 0x55, 0xde, 0x27, 0xc2,
+    0xd6, 0xe9, 0xc6, 0x10, 0x5a, 0x06, 0xc3, 0x7d, 0x9c, 0x4a, 0x7f, 0x9d,
+    0x0d, 0xc0, 0xea, 0xc7, 0x71, 0x00, 0xc7, 0x9f, 0x75, 0xad, 0xd3, 0xf0,
+    0x61, 0xf4, 0x36, 0xeb, 0x69, 0x9d, 0x99, 0x59, 0x0d, 0x0a, 0x03, 0x19,
+    0xf2, 0xcd, 0xb2, 0x24, 0xbb, 0x1c, 0x36, 0x5e, 0x2a, 0xf8, 0x68, 0xd8,
+    0x14, 0x42, 0x16, 0x5a, 0xa2, 0xf4, 0xa6, 0x15, 0x4b, 0x72, 0x8e, 0x48,
+    0x82, 0x86, 0xc1, 0x15, 0x69, 0xfb, 0x0d, 0x30, 0x2d, 0xbc, 0xeb, 0x93,
+    0xf9, 0x54, 0x05, 0x25, 0x44, 0x1b, 0x9e, 0xee, 0x47, 0x49, 0xde, 0x00,
+    0x78, 0x1f, 0x1f, 0xa1, 0x80, 0xc9, 0x63, 0x98, 0x8a, 0xd8, 0x82, 0x44,
+    0xab, 0x5a, 0x4a, 0x76, 0x59, 0x58, 0x94, 0x85, 0x7f, 0xaa, 0xd7, 0xd7,
+    0xa8, 0x5d, 0xc2, 0x48, 0x53, 0xee, 0x23, 0x58, 0x55, 0x2b, 0x69, 0x95,
+    0x91, 0x99, 0xe5, 0x9b, 0x2c, 0xe0, 0xfb, 0xf2, 0x86, 0x82, 0x5b, 0xde,
+    0xc1, 0x36, 0x1e, 0x00, 0x14, 0x7a, 0x17, 0x62, 0xe3, 0xe1, 0x40, 0xfa,
+    0x77, 0x06, 0x0e, 0x04, 0x55, 0x65, 0x75, 0x27, 0x43, 0xb4, 0x94, 0xab,
+    0xcd, 0x67, 0x93, 0x19, 0x2f, 0x08, 0x3c, 0x66, 0x48, 0xbd, 0xfe, 0x5b,
+    0x42, 0x40, 0x23, 0xbd, 0x3d, 0x5e, 0x94, 0xfb, 0xb2, 0xfa, 0x94, 0xc7,
+    0x57, 0x2e, 0xee, 0xaf, 0x78, 0xef, 0x21, 0x8a, 0x38, 0xd5, 0x6c, 0x88,
+    0x37, 0xc5, 0x33, 0x8e, 0x1d, 0x02, 0x87, 0xdc, 0x16, 0x59, 0x93, 0x95,
+    0x83, 0x6a, 0x36, 0x67, 0x14, 0xc2, 0x8c, 0xb9, 0xfb, 0x55, 0x84, 0xba,
+    0x35, 0xc4, 0xef, 0x98, 0xd5, 0xb0, 0xcf, 0x13, 0x2b, 0xbe, 0x3b, 0x44,
+    0x7e, 0x81, 0xc9, 0xeb, 0xb0, 0xa5, 0x33, 0xbb, 0x75, 0x1d, 0x61, 0x57,
+    0x78, 0x9f, 0x0b, 0x5b, 0xa7, 0x18, 0x41, 0x68, 0x1b, 0x0d, 0xf6, 0x71,
+    0x29, 0xfe, 0x74, 0x37, 0x03, 0xab, 0x1d, 0xc4, 0x03, 0x1e, 0x7d, 0xd6,
+    0xb7, 0x4f, 0xc1, 0x87, 0xd0, 0xdb, 0xad, 0xa6, 0x76, 0x65, 0x64, 0x34,
+    0x28, 0x0c, 0x67, 0xcb, 0x36, 0xc8, 0x92, 0xec, 0x70, 0xd9, 0x78, 0xab,
+    0xe1, 0xa3, 0x60, 0x51, 0x08, 0x59, 0x6a, 0x8b, 0xd2, 0x98, 0x55, 0x2d,
+    0xca, 0x39, 0x22, 0x0a, 0x1b, 0x04, 0x55, 0xa7, 0xec, 0x34, 0xc0, 0xb6,
+    0xf3, 0xae, 0x4f, 0xe5, 0x50, 0x14, 0x95, 0x10, 0x6e, 0x7b, 0xb9, 0x1d,
+    0x27, 0x78, 0x01, 0xe0, 0x7c, 0x7e, 0x86, 0x03, 0x25, 0x8e, 0x62, 0x2b,
+    0x62, 0x09, 0x12, 0xad, 0x69, 0x29, 0xd9, 0x65, 0x62, 0x52, 0x15, 0xfe,
+    0xab, 0x5f, 0x5e, 0xa1, 0x77, 0x09, 0x21, 0x4f, 0xb8, 0x8d, 0x61, 0x54,
+    0xad, 0xa6, 0x56, 0x46, 0x67, 0x96, 0x6c, 0xb3, 0x83, 0xef, 0xca, 0x1a,
+    0x09, 0x6f, 0x7b, 0x04, 0xd8, 0x78, 0x00, 0x51, 0xe8, 0x5d, 0x8b, 0x8f,
+    0x85, 0x03, 0xe9, 0xdc, 0x18, 0x38, 0x11, 0x55, 0x95, 0xd4, 0x9d, 0x0e,
+    0xd2, 0x52, 0xaf, 0x35, 0x9e, 0x4c, 0x64, 0xbc, 0x20, 0xf1, 0x99, 0x22,
+    0xf7, 0xf9, 0x6d, 0x09, 0x00, 0x8e, 0xf4, 0xf5, 0x7a, 0x53, 0xee, 0xcb,
+    0xea, 0x53, 0x1d, 0x5c, 0xbb, 0xba, 0xbd, 0xe3, 0xbc, 0x86, 0x28, 0xe3,
+    0x55, 0xb2, 0x20, 0xdf, 0x14, 0xce, 0x38, 0x74, 0x0a, 0x1f, 0x70, 0x59,
+    0x66, 0x4e, 0x56, 0x0d, 0xa8, 0xd9, 0x9c, 0x53, 0x0a, 0x32, 0xe7, 0xed,
+    0x56, 0x12, 0xe8, 0xd7, 0x13, 0xbe, 0x63, 0x56, 0xc3, 0x3c, 0x4c, 0xae,
+    0xf8, 0xed, 0x11, 0xfa, 0x07, 0x27, 0xae, 0xc2, 0x94, 0xce, 0xed, 0xd4,
+    0x75, 0x85, 0x5d, 0xe2, 0x7c, 0x2d, 0x6e, 0x9c, 0x61, 0x05, 0xa0, 0x6c,
+    0x37, 0xd9, 0xc4, 0xa7, 0xf9, 0xd0, 0xdc, 0x0e, 0xac, 0x77, 0x10, 0x0c,
+    0x79, 0xf7, 0x5a, 0xdd, 0x3f, 0x06, 0x1f, 0x43, 0x6e, 0xb6, 0x99, 0xd9,
+    0x95, 0x90, 0xd0, 0xa0, 0x31, 0x9f, 0x2c, 0xdb, 0x22, 0x4b, 0xb1, 0xc3,
+    0x65, 0xe2, 0xaf, 0x86, 0x8d, 0x81, 0x44, 0x21, 0x65, 0xaa, 0x2f, 0x4a,
+    0x61, 0x54, 0xb7, 0x28, 0xe4, 0x88, 0x28, 0x6c, 0x11, 0x56, 0x9f, 0xb0,
+    0xd3, 0x02, 0xdb, 0xce, 0xb9, 0x3f, 0x95, 0x40, 0x52, 0x54, 0x41, 0xb9,
+    0xee, 0xe4, 0x74, 0x9d, 0xe0, 0x07, 0x81, 0xf1, 0xfa, 0x18, 0x0c, 0x96,
+    0x39, 0x88, 0xad, 0x88, 0x24, 0x4a, 0xb5, 0xa4, 0xa7, 0x65, 0x95, 0x89,
+    0x48, 0x57, 0xfa, 0xad, 0x7d, 0x7a, 0x85, 0xdc, 0x24, 0x85, 0x3e, 0xe2,
+    0x35, 0x85, 0x52, 0xb6, 0x99, 0x59, 0x19, 0x9e, 0x59, 0xb2, 0xce, 0x0f,
+    0xbf, 0x28, 0x68, 0x25, 0xbd, 0xec, 0x13, 0x61, 0xe0, 0x01, 0x47, 0xa1,
+    0x76, 0x2e, 0x3e, 0x14, 0x0f, 0xa7, 0x70, 0x60, 0xe0, 0x45, 0x56, 0x57,
+    0x52, 0x74, 0x3b, 0x49, 0x4a, 0xbc, 0xd6, 0x79, 0x31, 0x92, 0xf0, 0x83,
+    0xc6, 0x64, 0x8b, 0xdf, 0xe5, 0xb4, 0x24, 0x02, 0x3b, 0xd3, 0xd5, 0xe9,
+    0x4f, 0xbb, 0x2f, 0xa9, 0x4c, 0x75, 0x72, 0xee, 0xea, 0xf7, 0x8e, 0xf2,
+    0x18, 0xa3, 0x8d, 0x56, 0xc8, 0x83, 0x7c, 0x53, 0x38, 0xe1, 0xd0, 0x28,
+    0x7d, 0xc1, 0x65, 0x99, 0x39, 0x58, 0x36, 0xa3, 0x66, 0x71, 0x4c, 0x28,
+    0xcb, 0x9f, 0xb5, 0x58, 0x4b, 0xa3, 0x5c, 0x4e, 0xf9, 0x8d, 0x5b, 0x0c,
+    0xf1, 0x32, 0xbb, 0xe3, 0xb4, 0x47, 0xe8, 0x1c, 0x9e, 0xbb, 0x0a, 0x53,
+    0x3b, 0xb7, 0x51, 0xd6, 0x15, 0x77, 0x89, 0xf0, 0xb5, 0xba, 0x71, 0x84,
+    0x16, 0x81, 0xb0, 0xdf, 0x67, 0x12, 0x9f, 0xe7, 0x43, 0x70, 0x3a, 0xb1,
+    0xdc, 0x40, 0x31, 0xe7, 0xdd, 0x6b, 0x74, 0xfc, 0x18, 0x7d, 0x0d, 0xba,
+    0xda, 0x67, 0x66, 0x56, 0x43, 0x42, 0x80, 0xc6, 0x7c, 0xb3, 0x6c, 0x89,
+    0x2e, 0xc7, 0x0d, 0x97, 0x8a, 0xbe, 0x1a, 0x36, 0x05, 0x10, 0x85, 0x96,
+    0xa8, 0xbd, 0x29, 0x85, 0x52, 0xdc, 0xa3, 0x92, 0x20, 0xa1, 0xb0, 0x45,
+    0x5a, 0x7e, 0xc3, 0x4c, 0x0b, 0x6f, 0x3a, 0xe4, 0xfe, 0x55, 0x01, 0x49,
+    0x51, 0x06, 0xe7, 0xbb, 0x91, 0xd2, 0x77, 0x80, 0x1e, 0x07, 0xc7, 0xe8,
+    0x60, 0x32, 0x58, 0xe6, 0x22, 0xb6, 0x20, 0x91, 0x2a, 0xd6, 0x92, 0x9d,
+    0x96, 0x56, 0x25, 0x21, 0x5f, 0xea, 0xb5, 0xf5, 0xea, 0x17, 0x70, 0x92,
+    0x14, 0xfb, 0x88, 0xd6, 0x15, 0x4a, 0xda, 0x65, 0x64, 0x66, 0x79, 0x66,
+    0xcb, 0x38, 0x3e, 0xfc, 0xa1, 0xa0, 0x96, 0xf7, 0xb0, 0x4d, 0x87, 0x80,
+    0x05, 0x1e, 0x85, 0xd8, 0xb8, 0xf8, 0x50, 0x3e, 0x9d, 0xc1, 0x83, 0x81,
+    0x15, 0x59, 0x5d, 0x49, 0xd0, 0xed, 0x25, 0x2a, 0xf3, 0x59, 0xe4, 0xc6,
+    0x4b, 0xc2, 0x0f, 0x19, 0x92, 0x2f, 0x7f, 0x96, 0xd0, 0x90, 0x08, 0xef,
+    0x4f, 0x57, 0xa5, 0x3e, 0xec, 0xbe, 0xa5, 0x31, 0xd5, 0xcb, 0xbb, 0xab,
+    0xde, 0x3b, 0xc8, 0x62, 0x8e, 0x35, 0x5b, 0x22, 0x0d, 0xf1, 0x4c, 0xe3,
+    0x87, 0x40, 0xa1, 0xf7, 0x05, 0x96, 0x64, 0xe5, 0x60, 0xda, 0x8d, 0x99,
+    0xc5, 0x30, 0xa3, 0x2e, 0x7e, 0xd5, 0x61, 0x2e, 0x8d, 0x71, 0x3b, 0xe6,
+    0x35, 0x6c, 0x33, 0xc4, 0xca, 0xef, 0x8e, 0xd1, 0x1f, 0xa0, 0x72, 0x7a,
+    0xec, 0x29, 0x4c, 0xee, 0xdd, 0x47, 0x58, 0x55, 0xde, 0x27, 0xc2, 0xd6,
+    0xe9, 0xc6, 0x10, 0x5a, 0x06, 0xc3, 0x7d, 0x9c, 0x4a, 0x7f, 0x9d, 0x0d,
+    0xc0, 0xea, 0xc7, 0x71, 0x00, 0xc7, 0x9f, 0x75, 0xad, 0xd3, 0xf0, 0x61,
+    0xf4, 0x36, 0xeb, 0x69, 0x9d, 0x99, 0x59, 0x0d, 0x0a, 0x03, 0x19, 0xf2,
+    0xcd, 0xb2, 0x24, 0xbb, 0x1c, 0x36, 0x5e, 0x2a, 0xf8, 0x68, 0xd8, 0x14,
+    0x42, 0x16, 0x5a, 0xa2, 0xf4, 0xa6, 0x15, 0x4b, 0x72, 0x8e, 0x48, 0x82,
+    0x86, 0xc1, 0x15, 0x69, 0xfb, 0x0d, 0x30, 0x2d, 0xbc, 0xeb, 0x93, 0xf9,
+    0x54, 0x05, 0x25, 0x44, 0x1b, 0x9e, 0xee, 0x47, 0x49, 0xde, 0x00, 0x78,
+    0x1f, 0x1f, 0xa1, 0x80, 0xc9, 0x63, 0x98, 0x8a, 0xd8, 0x82, 0x44, 0xab,
+    0x5a, 0x4a, 0x76, 0x59, 0x58, 0x94, 0x85, 0x7f, 0xaa, 0xd7, 0xd7, 0xa8,
+    0x5d, 0xc2, 0x48, 0x53, 0xee, 0x23, 0x58, 0x55, 0x2b, 0x69, 0x95, 0x91,
+    0x99, 0xe5, 0x9b, 0x2c, 0xe0, 0xfb, 0xf2, 0x86, 0x82, 0x5b, 0xde, 0xc1,
+    0x36, 0x1e, 0x00, 0x14, 0x7a, 0x17, 0x62, 0xe3, 0xe1, 0x40, 0xfa, 0x77,
+    0x06, 0x0e, 0x04, 0x55, 0x65, 0x75, 0x27, 0x43, 0xb4, 0x94, 0xab, 0xcd,
+    0x67, 0x93, 0x19, 0x2f, 0x08, 0x3c, 0x66, 0x48, 0xbd, 0xfe, 0x5b, 0x42,
+    0x40, 0x23, 0xbd, 0x3d, 0x5e, 0x94, 0xfb, 0xb2, 0xfa, 0x94, 0xc7, 0x57,
+    0x2e, 0xee, 0xaf, 0x78, 0xef, 0x21, 0x8a, 0x38, 0xd5, 0x6c, 0x88, 0x37,
+    0xc5, 0x33, 0x8e, 0x1d, 0x02, 0x87, 0xdc, 0x16, 0x59, 0x93, 0x95, 0x83,
+    0x6a, 0x36, 0x67, 0x14, 0xc2, 0x8c, 0xb9, 0xfb, 0x55, 0x84, 0xba, 0x35,
+    0xc4, 0xef, 0x98, 0xd5, 0xb0, 0xcf, 0x13, 0x2b, 0xbe, 0x3b, 0x44, 0x7e,
+    0x81, 0xca,
+};
+static_assert(sizeof(kBytesTestReadSymbol13) == kNumBytesTestReadSymbol13, "");
+
+// The kBytesTestReadSymbol14[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][15] = {
+//   // pmf: 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14, 1/14,
+//   // 1/14, 1/14, 1/14
+//   { 32768 - 2341, 32768 - 4681, 32768 - 7022, 32768 - 9362, 32768 - 11703,
+//     32768 - 14043, 32768 - 16384, 32768 - 18725, 32768 - 21065,
+//     32768 - 23406, 32768 - 25746, 32768 - 28087, 32768 - 30427, 0, 0 },
+//   // pmf: 3/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28,
+//   // 2/28, 2/28, 1/28
+//   { 32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533, 32768 - 12873,
+//     32768 - 15214, 32768 - 17554, 32768 - 19895, 32768 - 22235,
+//     32768 - 24576, 32768 - 26917, 32768 - 29257, 32768 - 31598, 0, 0 },
+//   // pmf: 1/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28, 2/28,
+//   // 2/28, 2/28, 3/28
+//   { 32768 - 1170, 32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533,
+//     32768 - 12873, 32768 - 15214, 32768 - 17554, 32768 - 19895,
+//     32768 - 22235, 32768 - 24576, 32768 - 26917, 32768 - 29257, 0, 0 },
+//   // pmf: 1/28, 2/28, 2/28, 2/28, 2/28, 2/28, 3/28, 3/28, 2/28, 2/28, 2/28,
+//   // 2/28, 2/28, 1/28
+//   { 32768 - 1170, 32768 - 3511, 32768 - 5851, 32768 - 8192, 32768 - 10533,
+//     32768 - 12873, 32768 - 16384, 32768 - 19895, 32768 - 22235,
+//     32768 - 24576, 32768 - 26917, 32768 - 29257, 32768 - 31598, 0, 0 },
+// };
+// constexpr int kSymbols[28][4] = { { 0, 7, 13, 6 },    //
+//                                   { 1, 8, 12, 5 },    //
+//                                   { 2, 9, 11, 4 },    //
+//                                   { 3, 10, 10, 3 },   //
+//                                   { 4, 11, 9, 2 },    //
+//                                   { 5, 12, 8, 1 },    //
+//                                   { 6, 13, 7, 0 },    //
+//                                   { 7, 0, 6, 13 },    //
+//                                   { 8, 1, 5, 12 },    //
+//                                   { 9, 2, 4, 11 },    //
+//                                   { 10, 3, 3, 10 },   //
+//                                   { 11, 4, 2, 9 },    //
+//                                   { 12, 5, 1, 8 },    //
+//                                   { 13, 6, 0, 7 },    //
+//                                   { 0, 0, 13, 11 },   //
+//                                   { 2, 1, 12, 9 },    //
+//                                   { 4, 3, 10, 7 },    //
+//                                   { 6, 5, 8, 5 },     //
+//                                   { 8, 7, 6, 3 },     //
+//                                   { 10, 9, 4, 1 },    //
+//                                   { 12, 11, 2, 12 },  //
+//                                   { 1, 0, 13, 10 },   //
+//                                   { 3, 2, 11, 8 },    //
+//                                   { 5, 4, 9, 6 },     //
+//                                   { 7, 6, 7, 4 },     //
+//                                   { 9, 8, 5, 2 },     //
+//                                   { 11, 10, 3, 7 },   //
+//                                   { 13, 12, 1, 6 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 64; ++i) {
+//   for (int j = 0; j < 28; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 14);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol14 = 3455;
+constexpr uint8_t kBytesTestReadSymbol14[] = {
+    0x0a, 0xef, 0xeb, 0xb5, 0x78, 0x91, 0x0b, 0x9d, 0xee, 0x99, 0x14, 0x9c,
+    0xf4, 0x58, 0x86, 0xe8, 0x69, 0x7f, 0x06, 0x07, 0x60, 0xb0, 0x79, 0xbe,
+    0xea, 0xe5, 0x69, 0x1c, 0x67, 0x7a, 0x75, 0x91, 0x2f, 0x1d, 0x49, 0x4e,
+    0x15, 0x40, 0x56, 0x15, 0xa1, 0xff, 0x72, 0x2d, 0xa5, 0x40, 0x81, 0x21,
+    0x3d, 0x06, 0x78, 0xd2, 0x62, 0x8a, 0xf2, 0x63, 0x50, 0x9d, 0xbd, 0xa0,
+    0xd4, 0x14, 0x42, 0x76, 0x4f, 0x44, 0xbe, 0xb2, 0xa1, 0x0d, 0x4c, 0x75,
+    0xe4, 0x4a, 0xed, 0xf9, 0x7e, 0xb8, 0x7b, 0x5a, 0x26, 0x78, 0x5f, 0xe3,
+    0x86, 0x72, 0x64, 0x48, 0x76, 0x51, 0x7a, 0x77, 0x3b, 0xcf, 0xa2, 0x8d,
+    0x31, 0xec, 0xc1, 0xa7, 0xf9, 0x9a, 0x76, 0x00, 0x7c, 0x17, 0x40, 0x03,
+    0x12, 0xe8, 0xed, 0xbf, 0x39, 0xe2, 0xdd, 0x6d, 0xdc, 0xe2, 0x34, 0xdf,
+    0x0d, 0xa6, 0x86, 0x22, 0xca, 0x86, 0x5f, 0x57, 0x25, 0xc6, 0x57, 0x60,
+    0xc3, 0x06, 0xe9, 0xf0, 0x06, 0xd4, 0xc0, 0xb3, 0xfc, 0x5b, 0xcd, 0xa9,
+    0xc0, 0x51, 0x6e, 0x10, 0x0a, 0x5a, 0xfd, 0xbf, 0x92, 0xc8, 0x21, 0x0e,
+    0x83, 0x74, 0xfe, 0x01, 0xec, 0x24, 0x61, 0x9d, 0x9e, 0xb8, 0xb2, 0x04,
+    0xa7, 0xe9, 0xd6, 0xc7, 0x79, 0x5b, 0xaa, 0xdd, 0x94, 0x5d, 0x26, 0x61,
+    0x0b, 0xee, 0x66, 0xf4, 0xb2, 0xd1, 0x9b, 0xf0, 0xb4, 0x9b, 0x50, 0x4c,
+    0x4a, 0x57, 0xbc, 0xfe, 0x7e, 0xca, 0xfe, 0xa8, 0x22, 0x1b, 0x2f, 0x4a,
+    0x26, 0x32, 0x96, 0xfd, 0x03, 0x02, 0x1b, 0x7c, 0x1d, 0x6d, 0x42, 0x48,
+    0x2b, 0x11, 0x0d, 0x8f, 0x40, 0xb8, 0x15, 0xf1, 0xdd, 0x06, 0xf7, 0xa0,
+    0x1f, 0x0f, 0x75, 0xb1, 0x53, 0x73, 0x1f, 0xbf, 0x97, 0xf7, 0xa0, 0xcb,
+    0x5b, 0x98, 0xb7, 0x50, 0xa7, 0xc5, 0x23, 0x9b, 0x16, 0x0a, 0x2e, 0x03,
+    0x68, 0x3a, 0x92, 0x75, 0xb8, 0xb0, 0xd8, 0xda, 0x2e, 0x82, 0x61, 0x3f,
+    0xa0, 0x6e, 0x78, 0xe5, 0x7d, 0x14, 0xe5, 0x1f, 0x7b, 0xec, 0xb5, 0x14,
+    0xb7, 0xa0, 0x72, 0xdc, 0x1a, 0x23, 0xa4, 0x5b, 0xc5, 0xc2, 0x75, 0x6a,
+    0x7c, 0x36, 0xef, 0xf0, 0xd1, 0x5a, 0x34, 0x31, 0x0b, 0xae, 0x4c, 0x07,
+    0xc2, 0xb7, 0xab, 0xd5, 0x67, 0xed, 0x65, 0x5e, 0xa0, 0x7e, 0x16, 0x04,
+    0xc6, 0x1b, 0x74, 0x0f, 0xa9, 0x35, 0xe8, 0x71, 0x83, 0xca, 0xc3, 0x21,
+    0x74, 0xf5, 0xee, 0x71, 0xd1, 0x4c, 0xa2, 0x1d, 0xce, 0x16, 0x4b, 0x9b,
+    0xb0, 0x9f, 0x42, 0x08, 0x49, 0x6a, 0x82, 0x66, 0xe8, 0xb2, 0xce, 0xfd,
+    0x8e, 0xdb, 0x9e, 0x9e, 0xeb, 0x4b, 0x3d, 0xbb, 0xab, 0x61, 0xe4, 0x0d,
+    0x87, 0x8e, 0xe9, 0x7b, 0xe8, 0x57, 0x70, 0x8c, 0xab, 0x0c, 0x0f, 0x05,
+    0x4b, 0xca, 0x6d, 0xe7, 0x94, 0x2b, 0x29, 0x28, 0xfd, 0xfa, 0x11, 0x4c,
+    0x08, 0x51, 0xce, 0x45, 0x70, 0x87, 0x2b, 0xcf, 0x88, 0x80, 0x87, 0x38,
+    0x80, 0x5d, 0x2e, 0x8f, 0x47, 0xd8, 0x5e, 0x75, 0x66, 0xa7, 0x86, 0x5e,
+    0x98, 0xd4, 0x1b, 0x00, 0x11, 0xcf, 0x7b, 0xef, 0x8b, 0x17, 0x93, 0xe0,
+    0x3a, 0x90, 0x7d, 0x0b, 0x45, 0x34, 0x2a, 0x67, 0xa4, 0x0e, 0xab, 0xc3,
+    0x3b, 0x27, 0x68, 0x03, 0x4d, 0xcb, 0xd5, 0x87, 0x53, 0x37, 0xe5, 0xcc,
+    0xc3, 0x73, 0x4a, 0x2c, 0x5f, 0xdc, 0x8d, 0xba, 0x6c, 0x11, 0xa0, 0x35,
+    0xc6, 0xbe, 0xd9, 0xd6, 0x64, 0x2e, 0x4b, 0x85, 0xbf, 0x50, 0xdd, 0xa6,
+    0xa0, 0xa4, 0x23, 0xd7, 0x82, 0xb6, 0x65, 0x4e, 0xa8, 0xd4, 0x19, 0xa1,
+    0xe4, 0xc8, 0x4d, 0x69, 0x2a, 0x41, 0x4f, 0x1e, 0x46, 0xb1, 0xde, 0x64,
+    0x0b, 0xf8, 0x62, 0xfe, 0x27, 0xc5, 0x2e, 0x31, 0x0f, 0x40, 0xae, 0x64,
+    0x86, 0x2a, 0x36, 0x7e, 0x03, 0x01, 0x37, 0xf3, 0x36, 0x42, 0x3f, 0xaa,
+    0x0b, 0xdd, 0xa9, 0x3e, 0x09, 0xe2, 0xe9, 0xea, 0x15, 0x5b, 0x0d, 0x4b,
+    0xcc, 0x47, 0xa5, 0x24, 0xed, 0x0b, 0x3c, 0xb3, 0x6e, 0xc6, 0x1d, 0x47,
+    0x39, 0x30, 0xe6, 0xf6, 0xc7, 0xae, 0x6b, 0x25, 0x09, 0xce, 0xf2, 0x2f,
+    0xaf, 0x4d, 0x32, 0xac, 0x4f, 0xa4, 0xff, 0x39, 0x48, 0xbb, 0xe6, 0xdf,
+    0x93, 0x41, 0x00, 0x2a, 0x82, 0xd9, 0x81, 0x79, 0xc4, 0x65, 0xf3, 0x62,
+    0x17, 0x18, 0x37, 0xcf, 0xa0, 0xaa, 0xe5, 0xc6, 0x97, 0x84, 0x14, 0x1c,
+    0x7e, 0x36, 0x72, 0xe2, 0x35, 0x84, 0x39, 0x43, 0x7b, 0xbf, 0xaf, 0x94,
+    0x9a, 0xa2, 0xeb, 0xf9, 0xc4, 0x5c, 0x49, 0x5a, 0xef, 0x6b, 0xe6, 0x19,
+    0x0e, 0xac, 0x08, 0x43, 0x4d, 0x5a, 0x14, 0x7e, 0x27, 0x4a, 0xd1, 0x4a,
+    0x9b, 0x3f, 0xdc, 0x98, 0x5a, 0xcb, 0x40, 0x90, 0xdf, 0x56, 0xa1, 0x76,
+    0x12, 0x71, 0xe1, 0x20, 0x5e, 0xf1, 0xaa, 0xd7, 0xba, 0x6c, 0xfb, 0x1d,
+    0x20, 0xfe, 0xa0, 0x41, 0x65, 0x09, 0x5f, 0x8b, 0xde, 0x20, 0xb7, 0x26,
+    0xd5, 0xce, 0x83, 0x14, 0x0d, 0x28, 0x36, 0x86, 0xe1, 0x02, 0x86, 0xde,
+    0xf3, 0xc6, 0x44, 0x10, 0x04, 0x84, 0x9f, 0x18, 0x9b, 0xf1, 0x0a, 0xca,
+    0x41, 0x53, 0xa9, 0xa9, 0x6b, 0xa5, 0x95, 0x22, 0x1d, 0x17, 0x3b, 0xc0,
+    0x5f, 0xb7, 0x5e, 0xac, 0x73, 0x4e, 0x76, 0xaf, 0x4c, 0xb4, 0x4f, 0xf6,
+    0x3f, 0xa1, 0x20, 0x2e, 0xf7, 0xa8, 0x14, 0x0d, 0xc3, 0x50, 0x97, 0x25,
+    0xe0, 0xc4, 0x5c, 0x3e, 0xe6, 0xbe, 0xe9, 0xa4, 0x1e, 0x1d, 0xdb, 0x06,
+    0xc1, 0x15, 0xf2, 0x6d, 0xbf, 0x71, 0xf2, 0x0b, 0xd9, 0x75, 0x4b, 0x38,
+    0xf5, 0xe2, 0x69, 0x0d, 0x93, 0xa5, 0x8e, 0x4c, 0xc5, 0x2a, 0xb6, 0x45,
+    0x60, 0x77, 0xd6, 0x14, 0x39, 0x5e, 0x70, 0x9e, 0x8d, 0x07, 0x20, 0x1c,
+    0x05, 0xc9, 0xb0, 0x46, 0xf7, 0x6c, 0x3e, 0xf8, 0xf8, 0x0a, 0xad, 0x0b,
+    0x22, 0x5e, 0x32, 0xbd, 0x46, 0xbc, 0x06, 0x7b, 0x92, 0x36, 0x5a, 0x2b,
+    0xac, 0x68, 0x2d, 0x5a, 0xf4, 0xc2, 0x61, 0xe3, 0x9d, 0xf4, 0x5d, 0x59,
+    0x59, 0x98, 0xb7, 0x5a, 0x73, 0x08, 0xf6, 0x4f, 0x0a, 0x75, 0x04, 0x93,
+    0xc1, 0xe1, 0x9b, 0xe0, 0xb0, 0x2a, 0xf7, 0xdd, 0x8b, 0xae, 0xf5, 0x55,
+    0x28, 0x6b, 0x21, 0x9b, 0x02, 0x43, 0xbd, 0x36, 0x4d, 0xa5, 0x17, 0xbb,
+    0x97, 0xd4, 0x78, 0x1f, 0xe8, 0xd9, 0x98, 0x0e, 0x41, 0x96, 0x52, 0xab,
+    0xad, 0x91, 0x92, 0xae, 0x62, 0x5c, 0xe7, 0xeb, 0x24, 0x1b, 0xe8, 0x2a,
+    0xb2, 0xe8, 0xdc, 0x34, 0x7f, 0xe9, 0xa1, 0x4c, 0x4c, 0x13, 0xeb, 0x31,
+    0x29, 0xc3, 0xc4, 0xf5, 0xb4, 0x50, 0xb1, 0x8b, 0x08, 0xc3, 0x30, 0xf8,
+    0x40, 0xd8, 0x76, 0xd5, 0x4d, 0xf0, 0xc2, 0xd8, 0x67, 0x75, 0x01, 0x81,
+    0x2a, 0xe0, 0x6b, 0xc0, 0xf5, 0x30, 0x55, 0xb6, 0xa9, 0x52, 0x19, 0xc4,
+    0x73, 0x78, 0xc4, 0x9e, 0x13, 0x5f, 0xa7, 0x56, 0xb4, 0x07, 0x2c, 0x92,
+    0x85, 0x66, 0x5d, 0x00, 0x47, 0x32, 0x3c, 0x8b, 0xbf, 0x86, 0x9e, 0xe2,
+    0xfd, 0xf1, 0xf0, 0x15, 0x5a, 0x16, 0x44, 0xbc, 0x65, 0x7a, 0x8d, 0x78,
+    0x0c, 0xf9, 0x94, 0x1d, 0x83, 0x7c, 0xee, 0xc7, 0x71, 0x23, 0x42, 0x2d,
+    0xb3, 0xe4, 0x68, 0x31, 0xec, 0x17, 0x63, 0x27, 0xe3, 0x52, 0x9d, 0xd0,
+    0xcd, 0xd8, 0xd8, 0x86, 0xb4, 0x91, 0x8a, 0xa3, 0xcb, 0xa3, 0x76, 0xc7,
+    0x98, 0xda, 0xd6, 0xb8, 0x34, 0x1c, 0xf6, 0x72, 0x23, 0xd8, 0x1b, 0xbe,
+    0x2d, 0x05, 0xe1, 0x83, 0x01, 0x74, 0xc7, 0xe3, 0x54, 0x85, 0xec, 0xec,
+    0xfb, 0x3a, 0xa2, 0xf3, 0x21, 0x7a, 0x0b, 0x68, 0x91, 0x02, 0xd2, 0xa4,
+    0x40, 0x21, 0xef, 0x4f, 0xe5, 0x3d, 0x6d, 0x6e, 0xfb, 0xba, 0xb1, 0x90,
+    0x4f, 0x81, 0x07, 0x27, 0x5e, 0xa8, 0xab, 0xa8, 0x87, 0x38, 0x3c, 0xe5,
+    0x48, 0x29, 0x9e, 0x77, 0x4c, 0xb4, 0x9d, 0x91, 0x2d, 0x8a, 0x0a, 0x84,
+    0xdd, 0x93, 0x95, 0xdf, 0xd4, 0xa3, 0x8f, 0xb7, 0xaf, 0x07, 0xd3, 0x81,
+    0xbb, 0x0d, 0x89, 0x42, 0x92, 0x0b, 0x66, 0x39, 0x8b, 0x99, 0x36, 0x61,
+    0xbb, 0xe1, 0x05, 0xca, 0x68, 0xc8, 0x0f, 0xae, 0x9e, 0x7d, 0x75, 0x7f,
+    0x24, 0xef, 0xdc, 0x97, 0x8d, 0xb9, 0xa5, 0x7a, 0x3c, 0xc4, 0x49, 0x79,
+    0x47, 0x47, 0x61, 0x88, 0xaf, 0x96, 0x08, 0x11, 0x22, 0xff, 0xb7, 0x14,
+    0x12, 0x15, 0x14, 0x26, 0xa3, 0x03, 0x0e, 0xb2, 0xff, 0x57, 0x9e, 0xc0,
+    0x92, 0x4f, 0x4c, 0x69, 0xd4, 0xfe, 0xc1, 0x46, 0xc4, 0xe8, 0x64, 0x7f,
+    0x08, 0x38, 0x90, 0x15, 0x8f, 0xc2, 0xc8, 0xa8, 0x50, 0x7f, 0x74, 0x4a,
+    0xc3, 0x37, 0x52, 0x44, 0x25, 0x78, 0x19, 0x48, 0x00, 0xd1, 0x39, 0x43,
+    0x3a, 0x14, 0x72, 0x8c, 0x8e, 0xa2, 0xf8, 0x95, 0x1e, 0x56, 0x07, 0xdd,
+    0xcd, 0x89, 0xde, 0x71, 0xc3, 0x85, 0xc3, 0xcf, 0xe4, 0x6c, 0xf4, 0x43,
+    0x95, 0x49, 0x27, 0x25, 0x35, 0x1a, 0xb9, 0xf7, 0xc8, 0x20, 0xeb, 0x01,
+    0xbb, 0x49, 0x8d, 0xf4, 0xc0, 0x32, 0xbe, 0x74, 0x42, 0x07, 0x53, 0xd0,
+    0xf4, 0x4c, 0x79, 0xa8, 0xb7, 0xf9, 0x09, 0xfd, 0xeb, 0x02, 0x83, 0x26,
+    0x3b, 0x88, 0x1a, 0x41, 0x70, 0x95, 0x2f, 0x53, 0xc1, 0xc1, 0xa5, 0xbe,
+    0x23, 0x32, 0x8b, 0x48, 0xb8, 0xff, 0x4c, 0x6b, 0x6e, 0xbf, 0xd7, 0xe0,
+    0xf1, 0x3a, 0xfd, 0xd2, 0x1e, 0xa2, 0x11, 0x50, 0xa0, 0xfe, 0xd2, 0x3d,
+    0x20, 0xa6, 0x79, 0xdd, 0x32, 0xd2, 0x76, 0x44, 0xb6, 0x28, 0x2a, 0x13,
+    0x76, 0x4e, 0x57, 0x92, 0xa5, 0x01, 0x64, 0x30, 0x06, 0xf1, 0xba, 0x62,
+    0x5a, 0x59, 0xab, 0xf2, 0x15, 0xef, 0x3c, 0x24, 0x96, 0x14, 0x6f, 0xd4,
+    0x51, 0xee, 0x6d, 0xeb, 0x77, 0xad, 0xba, 0x03, 0xe0, 0xd2, 0x30, 0xbd,
+    0xbf, 0x06, 0x14, 0xa3, 0xad, 0xd7, 0x97, 0x20, 0x89, 0x63, 0x8f, 0x84,
+    0x0d, 0x87, 0x6d, 0x5b, 0xdf, 0x0c, 0x2d, 0x86, 0x77, 0x6b, 0x73, 0xd6,
+    0x34, 0x83, 0xe5, 0x15, 0x88, 0x3e, 0xbc, 0x4d, 0x2c, 0x96, 0xd1, 0x1a,
+    0x81, 0xf1, 0xb4, 0x6c, 0xaa, 0x52, 0x3a, 0x53, 0x52, 0xc6, 0x73, 0x1b,
+    0xe6, 0xaa, 0xd5, 0xc8, 0x91, 0xee, 0x72, 0xad, 0x66, 0x25, 0x61, 0xbd,
+    0xa7, 0x15, 0x46, 0x5d, 0x76, 0x4a, 0x47, 0x9b, 0x03, 0x44, 0xe5, 0x0c,
+    0xe8, 0x51, 0xca, 0x32, 0x3a, 0x8b, 0xe2, 0x54, 0x79, 0x4d, 0x51, 0x4e,
+    0xbb, 0x44, 0x2c, 0x30, 0xd1, 0xe6, 0xa1, 0xc9, 0x2c, 0x28, 0xdf, 0xa8,
+    0xa3, 0xdc, 0xdb, 0xd6, 0xef, 0x5b, 0x74, 0x07, 0xc1, 0xa4, 0x55, 0x37,
+    0xc6, 0xfc, 0xde, 0xf2, 0x35, 0xb3, 0xf2, 0x3f, 0xe8, 0x0c, 0xbe, 0x60,
+    0x72, 0x56, 0xde, 0x5f, 0x0d, 0xdd, 0x2e, 0x67, 0x63, 0x31, 0x23, 0xbc,
+    0xbe, 0x8d, 0x47, 0xdd, 0xa0, 0x38, 0xab, 0x04, 0xd7, 0xb7, 0x07, 0xf9,
+    0x5d, 0x5e, 0x27, 0xd0, 0x6e, 0xda, 0x01, 0xda, 0x8b, 0x3d, 0xe9, 0x89,
+    0xe4, 0xbb, 0xeb, 0x3d, 0xd2, 0xb1, 0x16, 0x16, 0xe6, 0x49, 0xb6, 0x28,
+    0x02, 0xc3, 0xd0, 0x57, 0x17, 0x4f, 0x2a, 0x9b, 0x42, 0x74, 0x1d, 0x38,
+    0xc4, 0x19, 0xdd, 0xad, 0xcf, 0x58, 0xd2, 0x0f, 0x94, 0x56, 0x20, 0xfa,
+    0xf1, 0x34, 0xb2, 0x5b, 0x44, 0x6a, 0x07, 0xc6, 0xd1, 0xb2, 0xa9, 0x48,
+    0xe9, 0x4d, 0x4b, 0x19, 0xcc, 0x6f, 0x9a, 0xab, 0x57, 0x22, 0x47, 0xb9,
+    0xca, 0xb5, 0x98, 0x88, 0x58, 0x15, 0xe1, 0x37, 0x7b, 0x18, 0xdc, 0xea,
+    0x45, 0xad, 0xc7, 0xc3, 0xb4, 0xeb, 0xcb, 0x85, 0x2c, 0x31, 0xa6, 0x5e,
+    0x6a, 0x9d, 0xb6, 0x45, 0x19, 0x42, 0x5a, 0x2d, 0xe7, 0x15, 0x99, 0x8d,
+    0xe5, 0x5b, 0x09, 0x52, 0x8e, 0x4d, 0xf1, 0xec, 0xb3, 0xb1, 0xf5, 0xfe,
+    0x79, 0xb0, 0x4a, 0x4f, 0xb6, 0xbe, 0x18, 0x84, 0xe6, 0xaa, 0xb0, 0xe5,
+    0x76, 0x3c, 0x35, 0x51, 0xd2, 0xa6, 0xf3, 0xfb, 0xe3, 0x1b, 0xf5, 0xc4,
+    0x4f, 0x56, 0x3a, 0xc7, 0x41, 0x8d, 0xd7, 0x9e, 0x1e, 0xc9, 0x9c, 0xd8,
+    0xd4, 0xe3, 0x4f, 0xb5, 0xfd, 0x78, 0x5e, 0x60, 0xff, 0xd3, 0xdc, 0x00,
+    0xd6, 0x02, 0xba, 0x09, 0x8b, 0x93, 0xc9, 0xb4, 0x8e, 0x4e, 0x21, 0x27,
+    0x5e, 0x89, 0x6c, 0x31, 0x79, 0xfc, 0xf0, 0xd8, 0xac, 0x48, 0x52, 0x7d,
+    0xae, 0xc8, 0x4b, 0xef, 0x06, 0xde, 0xa4, 0xd3, 0x01, 0x46, 0xb2, 0xd6,
+    0x28, 0x45, 0xd9, 0xcb, 0x63, 0x32, 0x19, 0x3e, 0xbf, 0x13, 0x99, 0x7f,
+    0xdd, 0x0b, 0x25, 0x72, 0x57, 0x7a, 0x89, 0x68, 0xa4, 0xde, 0x98, 0xfc,
+    0xa8, 0xbc, 0xf2, 0xc1, 0x82, 0x28, 0x59, 0xf7, 0x6b, 0x83, 0x60, 0x57,
+    0x84, 0xdd, 0xec, 0x63, 0x73, 0xa9, 0x16, 0xb7, 0x1f, 0x0e, 0xd3, 0xaf,
+    0x2e, 0x14, 0xb0, 0xc6, 0x99, 0x79, 0xaa, 0x76, 0xd9, 0x14, 0x65, 0x09,
+    0x68, 0xb7, 0x9c, 0x56, 0x66, 0x37, 0x95, 0x6c, 0x25, 0x4a, 0x39, 0x37,
+    0xc7, 0xb2, 0xce, 0xc7, 0xd7, 0xf9, 0xe6, 0xc1, 0x29, 0x3e, 0xda, 0xf8,
+    0x62, 0x13, 0x9a, 0xaa, 0xc3, 0x95, 0xd8, 0xf0, 0xd5, 0x47, 0x4a, 0x9b,
+    0xcf, 0xef, 0x8c, 0x6f, 0xd7, 0x11, 0x3d, 0x58, 0xeb, 0x1d, 0x06, 0x37,
+    0x5e, 0x78, 0x7b, 0x26, 0x73, 0x63, 0x53, 0x8d, 0x3e, 0xd7, 0xf5, 0xe1,
+    0x79, 0x83, 0xff, 0x4f, 0x70, 0x03, 0x58, 0x0a, 0xe8, 0x26, 0x2e, 0x4f,
+    0x26, 0xd2, 0x39, 0x38, 0x84, 0x9d, 0x7a, 0x25, 0xb0, 0xc5, 0xe7, 0xf3,
+    0xc3, 0x62, 0xb1, 0x21, 0x49, 0xf6, 0xbb, 0x21, 0x2f, 0xbc, 0x1b, 0x7a,
+    0x93, 0x4c, 0x05, 0x1a, 0xcb, 0x58, 0xa1, 0x17, 0x67, 0x2d, 0x8c, 0xc8,
+    0x64, 0xfa, 0xfc, 0x4e, 0x65, 0xff, 0x74, 0x2c, 0x95, 0xc9, 0x5d, 0xea,
+    0x25, 0xa2, 0x93, 0x7a, 0x63, 0xf2, 0xa2, 0xf3, 0xcb, 0x06, 0x08, 0xa1,
+    0x67, 0xdd, 0xae, 0x0d, 0x81, 0x5e, 0x13, 0x77, 0xb1, 0x8d, 0xce, 0xa4,
+    0x5a, 0xdc, 0x7c, 0x3b, 0x4e, 0xbc, 0xb8, 0x52, 0xc3, 0x1a, 0x65, 0xe6,
+    0xa9, 0xdb, 0x64, 0x51, 0x94, 0x25, 0xa2, 0xde, 0x71, 0x59, 0x98, 0xde,
+    0x55, 0xb0, 0x95, 0x28, 0xe4, 0xdf, 0x1e, 0xcb, 0x3b, 0x1f, 0x5f, 0xe7,
+    0x9b, 0x04, 0xa4, 0xfb, 0x6b, 0xe1, 0x88, 0x4e, 0x6a, 0xab, 0x0e, 0x57,
+    0x63, 0xc3, 0x55, 0x1d, 0x2a, 0x6f, 0x3f, 0xbe, 0x31, 0xbf, 0x5c, 0x44,
+    0xf5, 0x63, 0xac, 0x74, 0x18, 0xdd, 0x79, 0xe1, 0xec, 0x99, 0xcd, 0x8d,
+    0x4e, 0x34, 0xfb, 0x5f, 0xd7, 0x85, 0xe6, 0x0f, 0xfd, 0x3d, 0xc0, 0x0d,
+    0x60, 0x2b, 0xa0, 0x98, 0xb9, 0x3c, 0x9b, 0x48, 0xe4, 0xe2, 0x12, 0x75,
+    0xe8, 0x96, 0xc3, 0x17, 0x9f, 0xcf, 0x0d, 0x8a, 0xc4, 0x85, 0x27, 0xda,
+    0xec, 0x84, 0xbe, 0xf0, 0x6d, 0xea, 0x4d, 0x30, 0x14, 0x6b, 0x2d, 0x62,
+    0x84, 0x5d, 0x9c, 0xb6, 0x33, 0x21, 0x93, 0xeb, 0xf1, 0x39, 0x97, 0xfd,
+    0xd0, 0xb2, 0x57, 0x25, 0x77, 0xa8, 0x96, 0x8a, 0x4d, 0xe9, 0x8f, 0xca,
+    0x8b, 0xcf, 0x2c, 0x18, 0x22, 0x85, 0x9f, 0x76, 0xb8, 0x36, 0x05, 0x78,
+    0x4d, 0xde, 0xc6, 0x37, 0x3a, 0x91, 0x6b, 0x71, 0xf0, 0xed, 0x3a, 0xf2,
+    0xe1, 0x4b, 0x0c, 0x69, 0x97, 0x9a, 0xa7, 0x6d, 0x91, 0x46, 0x50, 0x96,
+    0x8b, 0x79, 0xc5, 0x66, 0x63, 0x79, 0x56, 0xc2, 0x54, 0xa3, 0x93, 0x7c,
+    0x7b, 0x2c, 0xec, 0x7d, 0x7f, 0x9e, 0x6c, 0x12, 0x93, 0xed, 0xaf, 0x86,
+    0x21, 0x39, 0xaa, 0xac, 0x39, 0x5d, 0x8f, 0x0d, 0x54, 0x74, 0xa9, 0xbc,
+    0xfe, 0xf8, 0xc6, 0xfd, 0x71, 0x13, 0xd5, 0x8e, 0xb1, 0xd0, 0x63, 0x75,
+    0xe7, 0x87, 0xb2, 0x67, 0x36, 0x35, 0x38, 0xd3, 0xed, 0x7f, 0x5e, 0x17,
+    0x98, 0x3f, 0xf4, 0xf7, 0x00, 0x35, 0x80, 0xae, 0x82, 0x62, 0xe4, 0xf2,
+    0x6d, 0x23, 0x93, 0x88, 0x49, 0xd7, 0xa2, 0x5b, 0x0c, 0x5e, 0x7f, 0x3c,
+    0x36, 0x2b, 0x12, 0x14, 0x9f, 0x6b, 0xb2, 0x12, 0xfb, 0xc1, 0xb7, 0xa9,
+    0x34, 0xc0, 0x51, 0xac, 0xb5, 0x8a, 0x11, 0x76, 0x72, 0xd8, 0xcc, 0x86,
+    0x4f, 0xaf, 0xc4, 0xe6, 0x5f, 0xf7, 0x42, 0xc9, 0x5c, 0x95, 0xde, 0xa2,
+    0x5a, 0x29, 0x37, 0xa6, 0x3f, 0x2a, 0x2f, 0x3c, 0xb0, 0x60, 0x8a, 0x16,
+    0x7d, 0xda, 0xe0, 0xd8, 0x15, 0xe1, 0x37, 0x7b, 0x18, 0xdc, 0xea, 0x45,
+    0xad, 0xc7, 0xc3, 0xb4, 0xeb, 0xcb, 0x85, 0x2c, 0x31, 0xa6, 0x5e, 0x6a,
+    0x9d, 0xb6, 0x45, 0x19, 0x42, 0x5a, 0x2d, 0xe7, 0x15, 0x99, 0x8d, 0xe5,
+    0x5b, 0x09, 0x52, 0x8e, 0x4d, 0xf1, 0xec, 0xb3, 0xb1, 0xf5, 0xfe, 0x79,
+    0xb0, 0x4a, 0x4f, 0xb6, 0xbe, 0x18, 0x84, 0xe6, 0xaa, 0xb0, 0xe5, 0x76,
+    0x3c, 0x35, 0x51, 0xd2, 0xa6, 0xf3, 0xfb, 0xe3, 0x1b, 0xf5, 0xc4, 0x4f,
+    0x56, 0x3a, 0xc7, 0x41, 0x8d, 0xd7, 0x9e, 0x1e, 0xc9, 0x9c, 0xd8, 0xd4,
+    0xe3, 0x4f, 0xb5, 0xfd, 0x78, 0x5e, 0x60, 0xff, 0xd3, 0xdc, 0x00, 0xd6,
+    0x02, 0xba, 0x09, 0x8b, 0x93, 0xc9, 0xb4, 0x8e, 0x4e, 0x21, 0x27, 0x5e,
+    0x89, 0x6c, 0x31, 0x79, 0xfc, 0xf0, 0xd8, 0xac, 0x48, 0x52, 0x7d, 0xae,
+    0xc8, 0x4b, 0xef, 0x06, 0xde, 0xa4, 0xd3, 0x01, 0x46, 0xb2, 0xd6, 0x28,
+    0x45, 0xd9, 0xcb, 0x63, 0x32, 0x19, 0x3e, 0xbf, 0x13, 0x99, 0x7f, 0xdd,
+    0x0b, 0x25, 0x72, 0x57, 0x7a, 0x89, 0x68, 0xa4, 0xde, 0x98, 0xfc, 0xa8,
+    0xbc, 0xf2, 0xc1, 0x82, 0x28, 0x59, 0xf7, 0x6b, 0x83, 0x60, 0x57, 0x84,
+    0xdd, 0xec, 0x63, 0x73, 0xa9, 0x16, 0xb7, 0x1f, 0x0e, 0xd3, 0xaf, 0x2e,
+    0x14, 0xb0, 0xc6, 0x99, 0x79, 0xaa, 0x76, 0xd9, 0x14, 0x65, 0x09, 0x68,
+    0xb7, 0x9c, 0x56, 0x66, 0x37, 0x95, 0x6c, 0x25, 0x4a, 0x39, 0x37, 0xc7,
+    0xb2, 0xce, 0xc7, 0xd7, 0xf9, 0xe6, 0xc1, 0x29, 0x3e, 0xda, 0xf8, 0x62,
+    0x13, 0x9a, 0xaa, 0xc3, 0x95, 0xd8, 0xf0, 0xd5, 0x47, 0x4a, 0x9b, 0xcf,
+    0xef, 0x8c, 0x6f, 0xd7, 0x11, 0x3d, 0x58, 0xeb, 0x1d, 0x06, 0x37, 0x5e,
+    0x78, 0x7b, 0x26, 0x73, 0x63, 0x53, 0x8d, 0x3e, 0xd7, 0xf5, 0xe1, 0x79,
+    0x83, 0xff, 0x4f, 0x70, 0x03, 0x58, 0x0a, 0xe8, 0x26, 0x2e, 0x4f, 0x26,
+    0xd2, 0x39, 0x38, 0x84, 0x9d, 0x7a, 0x25, 0xb0, 0xc5, 0xe7, 0xf3, 0xc3,
+    0x62, 0xb1, 0x21, 0x49, 0xf6, 0xbb, 0x21, 0x2f, 0xbc, 0x1b, 0x7a, 0x93,
+    0x4c, 0x05, 0x1a, 0xcb, 0x58, 0xa1, 0x17, 0x67, 0x2d, 0x8c, 0xc8, 0x64,
+    0xfa, 0xfc, 0x4e, 0x65, 0xff, 0x74, 0x2c, 0x95, 0xc9, 0x5d, 0xea, 0x25,
+    0xa2, 0x93, 0x7a, 0x63, 0xf2, 0xa2, 0xf3, 0xcb, 0x06, 0x08, 0xa1, 0x67,
+    0xdd, 0xae, 0x0d, 0x81, 0x5e, 0x13, 0x77, 0xb1, 0x8d, 0xce, 0xa4, 0x5a,
+    0xdc, 0x7c, 0x3b, 0x4e, 0xbc, 0xb8, 0x52, 0xc3, 0x1a, 0x65, 0xe6, 0xa9,
+    0xdb, 0x64, 0x51, 0x94, 0x25, 0xa2, 0xde, 0x71, 0x59, 0x98, 0xde, 0x55,
+    0xb0, 0x95, 0x28, 0xe4, 0xdf, 0x1e, 0xcb, 0x3b, 0x1f, 0x5f, 0xe7, 0x9b,
+    0x04, 0xa4, 0xfb, 0x6b, 0xe1, 0x88, 0x4e, 0x6a, 0xab, 0x0e, 0x57, 0x63,
+    0xc3, 0x55, 0x1d, 0x2a, 0x6f, 0x3f, 0xbe, 0x31, 0xbf, 0x5c, 0x44, 0xf5,
+    0x63, 0xac, 0x74, 0x18, 0xdd, 0x79, 0xe1, 0xec, 0x99, 0xcd, 0x8d, 0x4e,
+    0x34, 0xfb, 0x5f, 0xd7, 0x85, 0xe6, 0x0f, 0xfd, 0x3d, 0xc0, 0x0d, 0x60,
+    0x2b, 0xa0, 0x98, 0xb9, 0x3c, 0x9b, 0x48, 0xe4, 0xe2, 0x12, 0x75, 0xe8,
+    0x96, 0xc3, 0x17, 0x9f, 0xcf, 0x0d, 0x8a, 0xc4, 0x85, 0x27, 0xda, 0xec,
+    0x84, 0xbe, 0xf0, 0x6d, 0xea, 0x4d, 0x30, 0x14, 0x6b, 0x2d, 0x62, 0x84,
+    0x5d, 0x9c, 0xb6, 0x33, 0x21, 0x93, 0xeb, 0xf1, 0x39, 0x97, 0xfd, 0xd0,
+    0xb2, 0x57, 0x25, 0x77, 0xa8, 0x96, 0x8a, 0x4d, 0xe9, 0x8f, 0xca, 0x8b,
+    0xcf, 0x2c, 0x18, 0x22, 0x85, 0x9f, 0x76, 0xb8, 0x36, 0x05, 0x78, 0x4d,
+    0xde, 0xc6, 0x37, 0x3a, 0x91, 0x6b, 0x71, 0xf0, 0xed, 0x3a, 0xf2, 0xe1,
+    0x4b, 0x0c, 0x69, 0x97, 0x9a, 0xa7, 0x6d, 0x91, 0x46, 0x50, 0x96, 0x8b,
+    0x79, 0xc5, 0x66, 0x63, 0x79, 0x56, 0xc2, 0x54, 0xa3, 0x93, 0x7c, 0x7b,
+    0x2c, 0xec, 0x7d, 0x7f, 0x9e, 0x6c, 0x12, 0x93, 0xed, 0xaf, 0x86, 0x21,
+    0x39, 0xaa, 0xac, 0x39, 0x5d, 0x8f, 0x0d, 0x54, 0x74, 0xa9, 0xbc, 0xfe,
+    0xf8, 0xc6, 0xfd, 0x71, 0x13, 0xd5, 0x8e, 0xb1, 0xd0, 0x63, 0x75, 0xe7,
+    0x87, 0xb2, 0x67, 0x36, 0x35, 0x38, 0xd3, 0xed, 0x7f, 0x5e, 0x17, 0x98,
+    0x3f, 0xf4, 0xf7, 0x00, 0x35, 0x80, 0xae, 0x82, 0x62, 0xe4, 0xf2, 0x6d,
+    0x23, 0x93, 0x88, 0x49, 0xd7, 0xa2, 0x5b, 0x0c, 0x5e, 0x7f, 0x3c, 0x36,
+    0x2b, 0x12, 0x14, 0x9f, 0x6b, 0xb2, 0x12, 0xfb, 0xc1, 0xb7, 0xa9, 0x34,
+    0xc0, 0x51, 0xac, 0xb5, 0x8a, 0x11, 0x76, 0x72, 0xd8, 0xcc, 0x86, 0x4f,
+    0xaf, 0xc4, 0xe6, 0x5f, 0xf7, 0x42, 0xc9, 0x5c, 0x95, 0xde, 0xa2, 0x5a,
+    0x29, 0x37, 0xa6, 0x3f, 0x2a, 0x2f, 0x3c, 0xb0, 0x60, 0x8a, 0x16, 0x7d,
+    0xda, 0xe0, 0xd8, 0x15, 0xe1, 0x37, 0x7b, 0x18, 0xdc, 0xea, 0x45, 0xad,
+    0xc7, 0xc3, 0xb4, 0xeb, 0xcb, 0x85, 0x2c, 0x31, 0xa6, 0x5e, 0x6a, 0x9d,
+    0xb6, 0x45, 0x19, 0x42, 0x5a, 0x2d, 0xe7, 0x15, 0x99, 0x8d, 0xe5, 0x5b,
+    0x09, 0x52, 0x8e, 0x4d, 0xf1, 0xec, 0xb3, 0xb1, 0xf5, 0xfe, 0x79, 0xb0,
+    0x4a, 0x4f, 0xb6, 0xbe, 0x18, 0x84, 0xe6, 0xaa, 0xb0, 0xe5, 0x76, 0x3c,
+    0x35, 0x51, 0xd2, 0xa6, 0xf3, 0xfb, 0xe3, 0x1b, 0xf5, 0xc4, 0x4f, 0x56,
+    0x3a, 0xc7, 0x41, 0x8d, 0xd7, 0x9e, 0x1e, 0xc9, 0x9c, 0xd8, 0xd4, 0xe3,
+    0x4f, 0xb5, 0xfd, 0x78, 0x5e, 0x60, 0xff, 0xd3, 0xdc, 0x00, 0xd6, 0x02,
+    0xba, 0x09, 0x8b, 0x93, 0xc9, 0xb4, 0x8e, 0x4e, 0x21, 0x27, 0x5e, 0x89,
+    0x6c, 0x31, 0x79, 0xfc, 0xf0, 0xd8, 0xac, 0x48, 0x52, 0x7d, 0xae, 0xc8,
+    0x4b, 0xef, 0x06, 0xde, 0xa4, 0xd3, 0x01, 0x46, 0xb2, 0xd6, 0x28, 0x45,
+    0xd9, 0xcb, 0x63, 0x32, 0x19, 0x3e, 0xbf, 0x13, 0x99, 0x7f, 0xdd, 0x0b,
+    0x25, 0x72, 0x57, 0x7a, 0x89, 0x68, 0xa4, 0xde, 0x98, 0xfc, 0xa8, 0xbc,
+    0xf2, 0xc1, 0x82, 0x28, 0x59, 0xf7, 0x6b, 0x83, 0x60, 0x57, 0x84, 0xdd,
+    0xec, 0x63, 0x73, 0xa9, 0x16, 0xb7, 0x1f, 0x0e, 0xd3, 0xaf, 0x2e, 0x14,
+    0xb0, 0xc6, 0x99, 0x79, 0xaa, 0x76, 0xd9, 0x14, 0x65, 0x09, 0x68, 0xb7,
+    0x9c, 0x56, 0x66, 0x37, 0x95, 0x6c, 0x25, 0x4a, 0x39, 0x37, 0xc7, 0xb2,
+    0xce, 0xc7, 0xd7, 0xf9, 0xe6, 0xc1, 0x29, 0x3e, 0xda, 0xf8, 0x62, 0x13,
+    0x9a, 0xaa, 0xc3, 0x95, 0xd8, 0xf0, 0xd5, 0x47, 0x4a, 0x9b, 0xcf, 0xef,
+    0x8c, 0x6f, 0xd7, 0x11, 0x3d, 0x58, 0xeb, 0x1d, 0x06, 0x37, 0x5e, 0x78,
+    0x7b, 0x26, 0x73, 0x63, 0x53, 0x8d, 0x3e, 0xd7, 0xf5, 0xe1, 0x79, 0x83,
+    0xff, 0x4f, 0x70, 0x03, 0x58, 0x0a, 0xe8, 0x26, 0x2e, 0x4f, 0x26, 0xd2,
+    0x39, 0x38, 0x84, 0x9d, 0x7a, 0x25, 0xb0, 0xc5, 0xe7, 0xf3, 0xc3, 0x62,
+    0xb1, 0x21, 0x49, 0xf6, 0xbb, 0x21, 0x2f, 0xbc, 0x1b, 0x7a, 0x93, 0x4c,
+    0x05, 0x1a, 0xcb, 0x58, 0xa1, 0x17, 0x67, 0x2d, 0x8c, 0xc8, 0x64, 0xfa,
+    0xfc, 0x4e, 0x65, 0xff, 0x74, 0x2c, 0x95, 0xc9, 0x5d, 0xea, 0x25, 0xa2,
+    0x93, 0x7a, 0x63, 0xf2, 0xa2, 0xf3, 0xcb, 0x06, 0x08, 0xa1, 0x67, 0xdd,
+    0xae, 0x0d, 0x81, 0x5e, 0x13, 0x77, 0xb1, 0x8d, 0xce, 0xa4, 0x5a, 0xdc,
+    0x7c, 0x3b, 0x4e, 0xbc, 0xb8, 0x52, 0xc3, 0x1a, 0x65, 0xe6, 0xa9, 0xdb,
+    0x64, 0x51, 0x94, 0x25, 0xa2, 0xde, 0x71, 0x59, 0x98, 0xde, 0x55, 0xb0,
+    0x95, 0x28, 0xe4, 0xdf, 0x1e, 0xcb, 0x3b, 0x1f, 0x5f, 0xe7, 0x9b, 0x04,
+    0xa4, 0xfb, 0x6b, 0xe1, 0x88, 0x4e, 0x6a, 0xab, 0x0e, 0x57, 0x63, 0xc3,
+    0x55, 0x1d, 0x2a, 0x6f, 0x3f, 0xbe, 0x31, 0xbf, 0x5c, 0x44, 0xf5, 0x63,
+    0xac, 0x74, 0x18, 0xdd, 0x79, 0xe1, 0xec, 0x99, 0xcd, 0x8d, 0x4e, 0x34,
+    0xfb, 0x5f, 0xd7, 0x85, 0xe6, 0x0f, 0xfd, 0x3d, 0xc0, 0x0d, 0x60, 0x2b,
+    0xa0, 0x98, 0xb9, 0x3c, 0x9b, 0x48, 0xe4, 0xe2, 0x12, 0x75, 0xe8, 0x96,
+    0xc3, 0x17, 0x9f, 0xcf, 0x0d, 0x8a, 0xc4, 0x85, 0x27, 0xda, 0xec, 0x84,
+    0xbe, 0xf0, 0x6d, 0xea, 0x4d, 0x30, 0x14, 0x6b, 0x2d, 0x62, 0x84, 0x5d,
+    0x9c, 0xb6, 0x33, 0x21, 0x93, 0xeb, 0xf1, 0x39, 0x97, 0xfd, 0xd0, 0xb2,
+    0x57, 0x25, 0x77, 0xa8, 0x96, 0x8a, 0x4d, 0xe9, 0x8f, 0xca, 0x8b, 0xcf,
+    0x2c, 0x18, 0x22, 0x85, 0x9f, 0x76, 0xb8, 0x36, 0x05, 0x78, 0x4d, 0xde,
+    0xc6, 0x37, 0x3a, 0x91, 0x6b, 0x71, 0xf0, 0xed, 0x3a, 0xf2, 0xe1, 0x4b,
+    0x0c, 0x69, 0x97, 0x9a, 0xa7, 0x6d, 0x91, 0x46, 0x50, 0x96, 0x8b, 0x79,
+    0xc5, 0x66, 0x63, 0x79, 0x56, 0xc2, 0x54, 0xa3, 0x93, 0x7c, 0x7b, 0x2c,
+    0xec, 0x7d, 0x7f, 0x9e, 0x6c, 0x12, 0x93, 0xed, 0xaf, 0x86, 0x21, 0x39,
+    0xaa, 0xac, 0x39, 0x5d, 0x8f, 0x0d, 0x54, 0x74, 0xa9, 0xbc, 0xfe, 0xf8,
+    0xc6, 0xfd, 0x71, 0x13, 0xd5, 0x8e, 0xb1, 0xd0, 0x63, 0x75, 0xe7, 0x87,
+    0xb2, 0x67, 0x36, 0x35, 0x38, 0xd3, 0xed, 0x7f, 0x5e, 0x17, 0x98, 0x3f,
+    0xf4, 0xf7, 0x00, 0x35, 0x80, 0xae, 0x82, 0x62, 0xe4, 0xf2, 0x6d, 0x23,
+    0x93, 0x88, 0x49, 0xd7, 0xa2, 0x5b, 0x0c, 0x5e, 0x7f, 0x3c, 0x36, 0x2b,
+    0x12, 0x14, 0x9f, 0x6b, 0xb2, 0x12, 0xfb, 0xc1, 0xb7, 0xa9, 0x34, 0xc0,
+    0x51, 0xac, 0xb5, 0x8a, 0x11, 0x76, 0x72, 0xd8, 0xcc, 0x86, 0x4f, 0xaf,
+    0xc4, 0xe6, 0x5f, 0xf7, 0x42, 0xc9, 0x5c, 0x95, 0xde, 0xa2, 0x70,
+};
+static_assert(sizeof(kBytesTestReadSymbol14) == kNumBytesTestReadSymbol14, "");
+
+// The kBytesTestReadSymbol16[] array was encoded by using the following libaom
+// code:
+//
+// aom_cdf_prob cdf[4][17] = {
+//   // pmf: 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16, 1/16,
+//   // 1/16, 1/16, 1/16, 1/16, 1/16
+//   { 32768 - 2048, 32768 - 4096, 32768 - 6144, 32768 - 8192, 32768 - 10240,
+//     32768 - 12288, 32768 - 14336, 32768 - 16384, 32768 - 18432,
+//     32768 - 20480, 32768 - 22528, 32768 - 24576, 32768 - 26624,
+//     32768 - 28672, 32768 - 30720, 0, 0 },
+//   // pmf: 3/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32,
+//   // 2/32, 2/32, 2/32, 2/32, 1/32
+//   { 32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216, 32768 - 11264,
+//     32768 - 13312, 32768 - 15360, 32768 - 17408, 32768 - 19456,
+//     32768 - 21504, 32768 - 23552, 32768 - 25600, 32768 - 27648,
+//     32768 - 29696, 32768 - 31744, 0, 0 },
+//   // pmf: 1/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32,
+//   // 2/32, 2/32, 2/32, 2/32, 3/32
+//   { 32768 - 1024, 32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216,
+//     32768 - 11264, 32768 - 13312, 32768 - 15360, 32768 - 17408,
+//     32768 - 19456, 32768 - 21504, 32768 - 23552, 32768 - 25600,
+//     32768 - 27648, 32768 - 29696, 0, 0 },
+//   // pmf: 1/32, 2/32, 2/32, 2/32, 2/32, 2/32, 2/32, 3/32, 3/32, 2/32, 2/32,
+//   // 2/32, 2/32, 2/32, 2/32, 1/32
+//   { 32768 - 1024, 32768 - 3072, 32768 - 5120, 32768 - 7168, 32768 - 9216,
+//     32768 - 11264, 32768 - 13312, 32768 - 16384, 32768 - 19456,
+//     32768 - 21504, 32768 - 23552, 32768 - 25600, 32768 - 27648,
+//     32768 - 29696, 32768 - 31744, 0, 0 },
+// };
+// constexpr int kSymbols[32][4] = { { 0, 8, 15, 7 },    //
+//                                   { 1, 9, 14, 6 },    //
+//                                   { 2, 10, 13, 5 },   //
+//                                   { 3, 11, 12, 4 },   //
+//                                   { 4, 12, 11, 3 },   //
+//                                   { 5, 13, 10, 2 },   //
+//                                   { 6, 14, 9, 1 },    //
+//                                   { 7, 15, 8, 0 },    //
+//                                   { 8, 0, 7, 15 },    //
+//                                   { 9, 1, 6, 14 },    //
+//                                   { 10, 2, 5, 13 },   //
+//                                   { 11, 3, 4, 12 },   //
+//                                   { 12, 4, 3, 11 },   //
+//                                   { 13, 5, 2, 10 },   //
+//                                   { 14, 6, 1, 9 },    //
+//                                   { 15, 7, 0, 8 },    //
+//                                   { 0, 0, 15, 13 },   //
+//                                   { 2, 1, 14, 11 },   //
+//                                   { 4, 3, 12, 9 },    //
+//                                   { 6, 5, 10, 7 },    //
+//                                   { 8, 7, 8, 5 },     //
+//                                   { 10, 9, 6, 3 },    //
+//                                   { 12, 11, 4, 1 },   //
+//                                   { 14, 13, 2, 14 },  //
+//                                   { 1, 0, 15, 12 },   //
+//                                   { 3, 2, 13, 10 },   //
+//                                   { 5, 4, 11, 8 },    //
+//                                   { 7, 6, 9, 6 },     //
+//                                   { 9, 8, 7, 4 },     //
+//                                   { 11, 10, 5, 2 },   //
+//                                   { 13, 12, 3, 8 },   //
+//                                   { 15, 14, 1, 7 } };
+// const unsigned int kBufferSize = 65536;
+// uint8_t bw_buffer[kBufferSize];
+// aom_writer bw;
+// bw.allow_update_cdf = 1;
+// aom_start_encode(&bw, bw_buffer);
+// for (int i = 0; i < 48; ++i) {
+//   for (int j = 0; j < 32; ++j) {
+//     for (int k = 0; k < 4; ++k) {
+//       aom_write_symbol(&bw, kSymbols[j][k], cdf[k], 16);
+//     }
+//   }
+// }
+// aom_stop_encode(&bw);
+// printf("constexpr size_t kNumBytes = %u;\n", bw.pos);
+// printf("constexpr uint8_t kBytes[] = {");
+// int count = 0;
+// for (unsigned int i = 0; i < bw.pos; ++i) {
+//   if (count++ % 12 == 0) {
+//     printf("\n    ");
+//   } else {
+//     printf(" ");
+//   }
+//   printf("0x%02x,", bw_buffer[i]);
+// }
+// printf("\n};\n");
+
+constexpr size_t kNumBytesTestReadSymbol16 = 3120;
+constexpr uint8_t kBytesTestReadSymbol16[] = {
+    0x09, 0x2c, 0xb8, 0x5a, 0xe4, 0xe6, 0xc6, 0x1f, 0x3e, 0xa7, 0x50, 0xbf,
+    0x19, 0x26, 0xbf, 0x20, 0xc3, 0xa2, 0x08, 0xdf, 0x44, 0xd9, 0x4d, 0x8c,
+    0xf7, 0xbf, 0x6b, 0x6d, 0x22, 0x97, 0x8e, 0xd7, 0x93, 0xad, 0x33, 0xe3,
+    0x7f, 0x5b, 0x71, 0x03, 0x6b, 0x4e, 0xbf, 0xf5, 0x38, 0xbe, 0xba, 0x6c,
+    0x0d, 0x28, 0xca, 0x74, 0x2d, 0x1d, 0x3f, 0x91, 0xad, 0x7e, 0x98, 0x5c,
+    0xa7, 0x39, 0x5e, 0x7c, 0x43, 0x2b, 0x88, 0xb2, 0x81, 0x91, 0xad, 0x62,
+    0x14, 0xc6, 0x0a, 0x81, 0x15, 0x1f, 0x4e, 0xd5, 0xc1, 0x5c, 0x43, 0x35,
+    0xc3, 0xe6, 0x3d, 0xaa, 0xc3, 0xb5, 0x95, 0x01, 0xbd, 0x2d, 0x21, 0x04,
+    0x14, 0x79, 0x7a, 0x02, 0x7e, 0xb8, 0x09, 0x20, 0x06, 0x82, 0xc8, 0x6f,
+    0x29, 0x2c, 0xb2, 0x9b, 0xe2, 0x8d, 0xf5, 0x56, 0xf5, 0x64, 0xf4, 0xd7,
+    0xfe, 0x24, 0x29, 0xb6, 0x35, 0x16, 0x08, 0x26, 0xc0, 0xf0, 0xfd, 0x33,
+    0x04, 0x6f, 0x70, 0x85, 0x3a, 0xac, 0x8f, 0xab, 0x48, 0xce, 0x04, 0xc1,
+    0x0a, 0x4c, 0xb6, 0xaa, 0x83, 0x39, 0xc1, 0xf6, 0x00, 0xb8, 0x56, 0x4e,
+    0xa2, 0xd1, 0x19, 0x70, 0x6a, 0x2b, 0x86, 0xef, 0xbd, 0x11, 0x27, 0x54,
+    0x52, 0x01, 0xa2, 0x3f, 0x53, 0x0e, 0x5b, 0x23, 0x3c, 0x90, 0x82, 0xaf,
+    0x9d, 0x79, 0xb5, 0x5e, 0x7e, 0x2e, 0x6e, 0xad, 0x3d, 0xe9, 0x3a, 0xff,
+    0xd7, 0x59, 0x40, 0xa3, 0x56, 0xa9, 0x5e, 0x52, 0xda, 0x04, 0x74, 0x09,
+    0x47, 0x7c, 0x6c, 0x4b, 0xad, 0x00, 0x8b, 0xbc, 0x33, 0x16, 0x49, 0xf6,
+    0xa5, 0x11, 0x8d, 0xb4, 0xbc, 0x28, 0xea, 0x1b, 0x34, 0x1e, 0xb7, 0x1e,
+    0xbf, 0x50, 0xe3, 0x60, 0xad, 0x41, 0xe0, 0x19, 0xfa, 0xa4, 0x23, 0x98,
+    0x48, 0x23, 0xad, 0xfa, 0xdb, 0x3c, 0x0a, 0x15, 0xeb, 0xf5, 0xf1, 0x43,
+    0xf2, 0xfd, 0x42, 0xf2, 0xd0, 0x3f, 0xa6, 0x3b, 0xc8, 0x81, 0x52, 0xba,
+    0xcf, 0x2d, 0xff, 0x2c, 0x24, 0x13, 0x62, 0x78, 0x01, 0xd8, 0xcb, 0xfc,
+    0xda, 0x70, 0x58, 0xad, 0xf1, 0xe6, 0x30, 0x47, 0x39, 0xc6, 0xf0, 0xbc,
+    0xe4, 0x89, 0x49, 0x46, 0x79, 0xde, 0xac, 0xde, 0xbd, 0x97, 0x18, 0x8f,
+    0x17, 0x07, 0xc1, 0xaf, 0xf8, 0xc1, 0x45, 0x95, 0x50, 0x36, 0x4d, 0x16,
+    0x35, 0x92, 0x2b, 0x5a, 0x71, 0x81, 0x59, 0xe5, 0x7f, 0xba, 0x10, 0xc9,
+    0x49, 0xd4, 0xeb, 0x64, 0x08, 0x54, 0x8b, 0xfa, 0xb3, 0xc8, 0x3a, 0xd7,
+    0xa6, 0xa9, 0xf2, 0xae, 0x04, 0xf8, 0x55, 0x5c, 0xff, 0x2d, 0x17, 0x53,
+    0x37, 0xc5, 0x36, 0xd8, 0x42, 0xd7, 0x47, 0xd8, 0x00, 0x99, 0x9c, 0x5d,
+    0x9f, 0x34, 0xc2, 0x09, 0x6b, 0x1a, 0xf3, 0x2f, 0xb0, 0xf8, 0x49, 0x54,
+    0x9d, 0x4b, 0xb8, 0xcf, 0xc5, 0x3b, 0x7f, 0x49, 0x9b, 0x40, 0xa9, 0xd3,
+    0x96, 0xe1, 0x6b, 0x87, 0x2d, 0x50, 0x76, 0x15, 0xd9, 0x9f, 0x87, 0x4f,
+    0x13, 0x26, 0xf2, 0xf8, 0xae, 0xd4, 0x63, 0x02, 0x0c, 0xcb, 0xe5, 0x63,
+    0x1c, 0x73, 0xdf, 0x57, 0x55, 0x16, 0x57, 0x3b, 0xfb, 0x9a, 0x06, 0x70,
+    0xfc, 0x9f, 0x29, 0x16, 0xec, 0x63, 0x34, 0x6f, 0x40, 0x1f, 0x54, 0x2a,
+    0xe7, 0x4a, 0x6f, 0xde, 0x86, 0xeb, 0x8c, 0x91, 0x3e, 0xfc, 0x6a, 0x48,
+    0xd1, 0x51, 0x33, 0xd7, 0xe1, 0x9d, 0xf8, 0x71, 0x21, 0x7b, 0x02, 0x38,
+    0x6a, 0xef, 0x30, 0x70, 0x38, 0x01, 0xc3, 0xef, 0x5d, 0x4f, 0xd3, 0x37,
+    0x2d, 0xe0, 0x4f, 0x4b, 0x72, 0xbc, 0xde, 0x9f, 0x32, 0x97, 0xe2, 0x55,
+    0x5e, 0x59, 0x5d, 0xa2, 0x9f, 0x5a, 0x04, 0x7c, 0x13, 0xe1, 0x35, 0x62,
+    0x4a, 0x10, 0x24, 0x55, 0x63, 0xb8, 0x8f, 0x66, 0xbc, 0x04, 0x08, 0x4e,
+    0xcc, 0xdc, 0x1f, 0x88, 0xc5, 0xcf, 0x8a, 0x7e, 0x24, 0x3e, 0x6f, 0x58,
+    0xcb, 0x44, 0x3c, 0x18, 0x64, 0xd9, 0x84, 0xa8, 0x1c, 0x0b, 0x20, 0xf4,
+    0x8b, 0x8b, 0x4b, 0xf8, 0x39, 0x8b, 0x01, 0x3a, 0x0b, 0x27, 0x67, 0xf8,
+    0x0f, 0xbd, 0xb3, 0x32, 0xce, 0xef, 0xbc, 0x8c, 0xa3, 0x31, 0xee, 0x0b,
+    0xdb, 0xc7, 0xc3, 0x43, 0x80, 0xe4, 0x7c, 0x9b, 0x89, 0xa4, 0x6b, 0x23,
+    0x2f, 0xa8, 0x28, 0xe0, 0x55, 0x30, 0x6e, 0xe7, 0xc9, 0x50, 0x1d, 0xbf,
+    0x67, 0xc8, 0x74, 0x58, 0x0f, 0xdb, 0xa6, 0x1f, 0xa6, 0xfd, 0xf0, 0x75,
+    0xea, 0x62, 0xd5, 0x44, 0xa2, 0x7e, 0xed, 0x63, 0xba, 0x7c, 0x5d, 0xb7,
+    0x16, 0x84, 0x30, 0x5d, 0xc2, 0xd3, 0x39, 0x61, 0x60, 0x0a, 0xb9, 0x34,
+    0x5e, 0x54, 0xf4, 0x34, 0x77, 0x22, 0x05, 0x41, 0x6b, 0x6a, 0x13, 0xc3,
+    0x10, 0x03, 0x8a, 0x78, 0xd2, 0x81, 0xac, 0x49, 0x31, 0xc8, 0xee, 0x15,
+    0xc3, 0x42, 0x3b, 0x00, 0xf6, 0x05, 0x92, 0x82, 0x6e, 0x73, 0xb4, 0xfa,
+    0xab, 0xe0, 0x2e, 0xe9, 0x5d, 0x89, 0x43, 0x0c, 0x4d, 0x88, 0x0c, 0xf1,
+    0xa4, 0x19, 0x59, 0xa0, 0x69, 0x0c, 0xfc, 0xf9, 0x9a, 0xbc, 0x3b, 0x2e,
+    0x3b, 0x29, 0xf8, 0xd7, 0x79, 0x11, 0xb2, 0x66, 0x26, 0x57, 0x34, 0x06,
+    0xb8, 0x36, 0x41, 0xca, 0x01, 0x10, 0xca, 0x06, 0xee, 0xb6, 0xf7, 0x1d,
+    0x0d, 0x88, 0xab, 0x07, 0xbe, 0x06, 0x8c, 0x1c, 0xa2, 0x76, 0x5e, 0xdb,
+    0x60, 0xa4, 0x43, 0x17, 0x31, 0xc3, 0x4b, 0x0a, 0x01, 0x80, 0xa7, 0xf6,
+    0xe6, 0x78, 0x64, 0x85, 0xb0, 0x8a, 0x28, 0x34, 0x82, 0x98, 0x29, 0x3f,
+    0xde, 0x07, 0x9a, 0x80, 0xcf, 0xe3, 0x6f, 0x23, 0x57, 0x79, 0x11, 0xb2,
+    0x61, 0x6d, 0x98, 0x26, 0xeb, 0x3b, 0xbf, 0xaa, 0x98, 0x62, 0xbb, 0xfd,
+    0x21, 0x76, 0xe5, 0xc5, 0xe0, 0x09, 0x21, 0x65, 0x72, 0x94, 0xd3, 0x8a,
+    0xcd, 0xfb, 0xec, 0x6e, 0x57, 0xd4, 0x2a, 0x92, 0xd1, 0xe9, 0x16, 0x46,
+    0xa2, 0x38, 0xae, 0x4b, 0x7e, 0xa7, 0x0c, 0x26, 0x9d, 0x96, 0xd7, 0x49,
+    0xa7, 0x02, 0x2b, 0x22, 0x9a, 0x39, 0x38, 0x11, 0xb8, 0xb3, 0xd5, 0x09,
+    0xf9, 0x70, 0xb4, 0x1c, 0x4e, 0xe3, 0xba, 0xa0, 0x78, 0x76, 0x6d, 0xc4,
+    0xab, 0x96, 0x3e, 0x98, 0x04, 0x4e, 0x50, 0x20, 0xd9, 0xfa, 0xea, 0xe2,
+    0x99, 0x50, 0x84, 0x20, 0x18, 0x69, 0xbb, 0x6e, 0x41, 0x9d, 0x18, 0x71,
+    0x15, 0x19, 0xd2, 0xf2, 0xa5, 0x69, 0x54, 0x8e, 0x60, 0x75, 0xd4, 0xe7,
+    0xdb, 0xe1, 0x43, 0xfd, 0x2e, 0x21, 0x4f, 0xff, 0x98, 0x8b, 0x08, 0x74,
+    0xca, 0x29, 0x7e, 0x3f, 0x2f, 0x6a, 0xf9, 0xe6, 0x49, 0x1d, 0xc6, 0x0b,
+    0x76, 0xc9, 0x22, 0xc3, 0x4f, 0xaf, 0xa8, 0xf9, 0xd6, 0x9c, 0x9a, 0x64,
+    0xec, 0xb3, 0x2c, 0x0f, 0x3e, 0x93, 0xc4, 0xb6, 0xd7, 0x36, 0x28, 0x04,
+    0xe5, 0x81, 0x48, 0x14, 0x9f, 0x4e, 0xc5, 0x9b, 0xd7, 0xc0, 0x0e, 0x35,
+    0xab, 0x49, 0xd3, 0x84, 0x9f, 0x5c, 0x93, 0x94, 0xa6, 0xd2, 0xb5, 0x83,
+    0x9d, 0x38, 0x0f, 0x85, 0x04, 0xa3, 0xb7, 0x23, 0x20, 0x93, 0x85, 0x48,
+    0x14, 0x0c, 0x22, 0x80, 0x92, 0x6c, 0xca, 0x3c, 0xc7, 0xfc, 0xa9, 0x88,
+    0x62, 0xbc, 0x2a, 0x91, 0x08, 0x5b, 0xb4, 0x60, 0xd1, 0x0f, 0x3c, 0x33,
+    0xc6, 0xe1, 0xf7, 0xca, 0xf7, 0xf9, 0xa1, 0x9b, 0xfa, 0xf7, 0x34, 0xe0,
+    0x54, 0xac, 0x53, 0x42, 0x30, 0x76, 0xc8, 0xc2, 0xcd, 0x61, 0x49, 0x87,
+    0x9c, 0x47, 0xf5, 0x98, 0xb5, 0x41, 0xf0, 0xad, 0xdb, 0x37, 0x06, 0xb8,
+    0x54, 0xa5, 0x26, 0x11, 0x4b, 0x18, 0xbb, 0xa4, 0xfb, 0x24, 0xd3, 0x14,
+    0x31, 0xfb, 0x56, 0x18, 0xd8, 0xc2, 0xd0, 0xd2, 0xab, 0xde, 0xdf, 0xa9,
+    0xdf, 0x9e, 0xa6, 0x56, 0x0d, 0x9f, 0xe4, 0x19, 0x15, 0x58, 0x18, 0xc6,
+    0x5e, 0x47, 0x05, 0x3a, 0x0e, 0x73, 0x68, 0x81, 0x39, 0x8c, 0x51, 0x1d,
+    0x04, 0x4e, 0x18, 0x54, 0xa5, 0x3e, 0x13, 0x4a, 0x15, 0xc2, 0x43, 0x90,
+    0xc2, 0x71, 0x8d, 0x53, 0x1b, 0xab, 0xe9, 0xbc, 0x69, 0x3e, 0x11, 0x46,
+    0x9d, 0xa4, 0xd3, 0x15, 0x80, 0xec, 0xe8, 0x31, 0x4f, 0x5a, 0x2a, 0x15,
+    0x3e, 0x7e, 0x7a, 0x44, 0x0e, 0x4a, 0xac, 0x9b, 0x46, 0x2f, 0x86, 0xf9,
+    0xea, 0x59, 0x4f, 0x15, 0xa0, 0x4b, 0xd1, 0xaa, 0xd8, 0x3a, 0x83, 0xb6,
+    0x25, 0x82, 0xb0, 0x44, 0x4a, 0x98, 0xbd, 0x10, 0xa2, 0xb0, 0x95, 0x02,
+    0xfa, 0x1f, 0xd3, 0x54, 0x1c, 0x0a, 0xb1, 0x31, 0x28, 0xec, 0x4c, 0xd2,
+    0x0c, 0xb9, 0xb0, 0xf4, 0x7a, 0x89, 0x63, 0x3c, 0x5f, 0xcf, 0x3c, 0xe8,
+    0xba, 0x21, 0x66, 0x20, 0x01, 0xcb, 0x1b, 0xc6, 0xf9, 0x54, 0x0f, 0xda,
+    0x4a, 0xcc, 0x81, 0x7b, 0x41, 0x81, 0xc0, 0x1f, 0xea, 0x9a, 0x9b, 0x96,
+    0x0d, 0x47, 0xdd, 0x16, 0x52, 0x5c, 0xaf, 0xae, 0x82, 0x3d, 0x18, 0x60,
+    0xfa, 0x34, 0xc2, 0x57, 0x2d, 0xc4, 0x2b, 0x2e, 0x41, 0xfe, 0xe7, 0x95,
+    0xcd, 0x1f, 0xbe, 0x88, 0x31, 0xc1, 0x07, 0x2c, 0xd3, 0xb1, 0xbb, 0xeb,
+    0x1d, 0xa3, 0x03, 0x1e, 0x70, 0xcc, 0x84, 0xe0, 0x65, 0x41, 0x0f, 0xf1,
+    0x7c, 0x95, 0x4b, 0x41, 0x43, 0x62, 0xad, 0x5d, 0xff, 0x4f, 0x92, 0xc8,
+    0xaa, 0x21, 0x23, 0xba, 0xa9, 0x90, 0xb5, 0xae, 0xc0, 0x1f, 0xae, 0x43,
+    0xf1, 0x79, 0x14, 0x30, 0x16, 0x1d, 0x2a, 0x6c, 0xd1, 0xd8, 0xb3, 0x38,
+    0x25, 0xd1, 0x66, 0xa5, 0x89, 0xc0, 0x8d, 0xc5, 0xa0, 0x6a, 0x7c, 0x64,
+    0xf8, 0x45, 0x1a, 0x76, 0x93, 0x4c, 0x56, 0x03, 0xb3, 0xa0, 0xc5, 0x40,
+    0xbc, 0x84, 0x98, 0x8d, 0xa4, 0xfe, 0x0b, 0x8c, 0x47, 0xa2, 0x88, 0x85,
+    0x2a, 0x89, 0xad, 0xd3, 0x16, 0x5b, 0x20, 0x02, 0x70, 0xbf, 0x72, 0x29,
+    0x0c, 0x0a, 0x9c, 0xac, 0x9c, 0x4d, 0xfa, 0x02, 0x5e, 0xe9, 0xe3, 0x52,
+    0x84, 0x54, 0x1f, 0xb7, 0xea, 0xb1, 0xc4, 0x2f, 0x69, 0xd1, 0x33, 0xc6,
+    0xb3, 0xee, 0xb0, 0x35, 0x1f, 0x19, 0x68, 0x2d, 0xef, 0xc1, 0xd3, 0x1c,
+    0xa8, 0x84, 0x54, 0x3c, 0x21, 0xed, 0x78, 0x35, 0x3f, 0x82, 0xb2, 0xa8,
+    0xe4, 0x25, 0x71, 0xfc, 0x1e, 0x1d, 0x36, 0xf4, 0xf4, 0x0f, 0x6f, 0x5b,
+    0xd9, 0x21, 0x13, 0x3a, 0x3d, 0x17, 0x45, 0x31, 0x78, 0x97, 0x99, 0x15,
+    0x87, 0xa9, 0xa6, 0x36, 0xf0, 0x20, 0xfa, 0xd5, 0x10, 0x01, 0x91, 0xa0,
+    0x4f, 0x28, 0x6a, 0x13, 0x04, 0xff, 0x97, 0x96, 0xf1, 0xfc, 0x1c, 0xc8,
+    0xcd, 0xe4, 0xbd, 0xe5, 0x40, 0x9a, 0x37, 0xc2, 0x01, 0x11, 0x2a, 0xc0,
+    0x0e, 0x58, 0x69, 0x29, 0xd0, 0x72, 0x26, 0x7c, 0x23, 0xec, 0x58, 0xfe,
+    0xbd, 0x15, 0x97, 0xe8, 0x29, 0x9f, 0x79, 0xb1, 0xfa, 0xac, 0x59, 0xe0,
+    0x78, 0x1c, 0xb4, 0x29, 0xee, 0x00, 0x39, 0x11, 0x0a, 0x2a, 0xb9, 0x98,
+    0x4e, 0xbf, 0x75, 0x9e, 0xe8, 0xbb, 0x4b, 0xe0, 0x6b, 0xab, 0x5b, 0x2f,
+    0x2d, 0xe3, 0xf8, 0x39, 0x91, 0x9b, 0xc9, 0x7b, 0xca, 0x81, 0x34, 0x6f,
+    0x84, 0x02, 0x22, 0x55, 0x80, 0x1c, 0xb0, 0xd2, 0x53, 0xa0, 0xe4, 0x4c,
+    0xf8, 0x47, 0xd8, 0xb1, 0xfd, 0x7a, 0x2b, 0x2f, 0xd0, 0x53, 0x3e, 0xf3,
+    0x63, 0xf5, 0x58, 0xb3, 0xc0, 0xf0, 0x39, 0x00, 0x08, 0x97, 0x4b, 0xe2,
+    0x46, 0x04, 0xa2, 0x39, 0x9c, 0xf2, 0x57, 0x17, 0x4a, 0xdd, 0x9f, 0x5e,
+    0xb1, 0x8b, 0x6b, 0x5d, 0x6e, 0x3e, 0x85, 0x34, 0x04, 0x96, 0x56, 0xe7,
+    0x4f, 0x6f, 0xd0, 0x31, 0xe7, 0x0c, 0xc8, 0x88, 0xdd, 0x5b, 0x14, 0x00,
+    0x60, 0x2a, 0x06, 0x18, 0xcd, 0x7f, 0xc9, 0xee, 0xd2, 0xd0, 0x8c, 0xc0,
+    0xed, 0x8f, 0x4a, 0x3e, 0x83, 0x52, 0x2e, 0x4a, 0xe9, 0xfa, 0x1f, 0x1a,
+    0xd5, 0xc0, 0x59, 0x4c, 0x8a, 0x2a, 0xab, 0x40, 0x2f, 0x84, 0xd2, 0x85,
+    0x70, 0x90, 0x96, 0xf3, 0x84, 0x6f, 0x1e, 0x81, 0x8c, 0x80, 0x03, 0x03,
+    0x2d, 0x36, 0x2e, 0x60, 0x79, 0x13, 0x63, 0x7f, 0xe7, 0xe3, 0x4a, 0x96,
+    0x08, 0xd8, 0x35, 0x15, 0x46, 0x8a, 0xe0, 0xb8, 0xc4, 0x7a, 0x28, 0x88,
+    0x52, 0xa8, 0x9a, 0xdd, 0x31, 0x65, 0xb2, 0x00, 0x24, 0xd9, 0xf4, 0x07,
+    0xea, 0xab, 0x7c, 0xe8, 0xa2, 0xea, 0xa7, 0x23, 0xd1, 0x93, 0x9e, 0xe7,
+    0x48, 0x34, 0x89, 0xf5, 0xb4, 0x45, 0x5e, 0xfa, 0xa6, 0xee, 0x32, 0x75,
+    0x8c, 0x56, 0x08, 0xcc, 0xeb, 0x5b, 0x05, 0xc2, 0x1d, 0x62, 0xa8, 0x5d,
+    0xaa, 0x50, 0xc2, 0x85, 0x85, 0x25, 0xb3, 0x5f, 0x60, 0xe7, 0x90, 0x1b,
+    0xa8, 0xb7, 0xf6, 0x83, 0x11, 0x07, 0x1f, 0xfc, 0xce, 0x58, 0x22, 0x8a,
+    0x3d, 0xa9, 0x8c, 0x18, 0x66, 0xa8, 0x32, 0x78, 0xa0, 0x16, 0x8a, 0xa2,
+    0x5d, 0x2f, 0x89, 0x18, 0x12, 0x88, 0xe6, 0x73, 0xc9, 0x5c, 0x5d, 0x2b,
+    0x76, 0x7d, 0x7a, 0xc6, 0x2d, 0xad, 0x75, 0xb8, 0xfa, 0x14, 0xd0, 0x12,
+    0x59, 0x5b, 0x9d, 0x3d, 0xbf, 0x40, 0xc7, 0x9c, 0x33, 0x22, 0x23, 0x75,
+    0x6c, 0x50, 0x01, 0x80, 0xa8, 0x18, 0x63, 0x35, 0xff, 0x27, 0xbb, 0x4b,
+    0x42, 0x33, 0x03, 0xb6, 0x3d, 0x28, 0xfa, 0x0d, 0x48, 0xb9, 0x2b, 0xa7,
+    0xe8, 0x7c, 0x6b, 0x57, 0x01, 0x65, 0x32, 0x28, 0xaa, 0xad, 0x00, 0xbe,
+    0x13, 0x4a, 0x15, 0xc2, 0x42, 0x5b, 0xce, 0x11, 0xbc, 0x7a, 0x06, 0x32,
+    0x00, 0x0c, 0x0c, 0xb4, 0xd8, 0xb9, 0x81, 0xe4, 0x4d, 0x8d, 0xff, 0x9f,
+    0x8d, 0x2a, 0x58, 0x23, 0x60, 0xd4, 0x55, 0x1a, 0x2b, 0x82, 0xe3, 0x11,
+    0xe8, 0xa2, 0x21, 0x4a, 0xa2, 0x6b, 0x74, 0xc5, 0x96, 0xc8, 0x00, 0x93,
+    0x67, 0xd0, 0x1f, 0xaa, 0xad, 0xf3, 0xa2, 0x8b, 0xaa, 0x9c, 0x8f, 0x46,
+    0x4e, 0x7b, 0x9d, 0x20, 0xd2, 0x27, 0xd6, 0xd1, 0x15, 0x7b, 0xea, 0x9b,
+    0xb8, 0xc9, 0xd6, 0x31, 0x58, 0x23, 0x33, 0xad, 0x6c, 0x17, 0x08, 0x75,
+    0x8a, 0xa1, 0x76, 0xa9, 0x43, 0x0a, 0x16, 0x14, 0x96, 0xcd, 0x7d, 0x83,
+    0x9e, 0x40, 0x6e, 0xa2, 0xdf, 0xda, 0x0c, 0x44, 0x1c, 0x7f, 0xf3, 0x39,
+    0x60, 0x8a, 0x28, 0xf6, 0xa6, 0x30, 0x61, 0x9a, 0xa0, 0xc9, 0xe2, 0x80,
+    0x5a, 0x2a, 0x89, 0x74, 0xbe, 0x24, 0x60, 0x4a, 0x23, 0x99, 0xcf, 0x25,
+    0x71, 0x74, 0xad, 0xd9, 0xf5, 0xeb, 0x18, 0xb6, 0xb5, 0xd6, 0xe3, 0xe8,
+    0x53, 0x40, 0x49, 0x65, 0x6e, 0x74, 0xf6, 0xfd, 0x03, 0x1e, 0x70, 0xcc,
+    0x88, 0x8d, 0xd5, 0xb1, 0x40, 0x06, 0x02, 0xa0, 0x61, 0x8c, 0xd7, 0xfc,
+    0x9e, 0xed, 0x2d, 0x08, 0xcc, 0x0e, 0xd8, 0xf4, 0xa3, 0xe9, 0x41, 0x30,
+    0x05, 0xc8, 0xbd, 0x3c, 0xa4, 0xb7, 0x09, 0x6f, 0x9c, 0xc8, 0xa2, 0xaa,
+    0xb4, 0x02, 0xf8, 0x4d, 0x28, 0x57, 0x09, 0x09, 0x6f, 0x38, 0x46, 0xf1,
+    0xe8, 0x18, 0xc8, 0x00, 0x30, 0x32, 0xd3, 0x62, 0xe6, 0x07, 0x91, 0x36,
+    0x37, 0xfe, 0x7e, 0x34, 0xa9, 0x60, 0x8d, 0x83, 0x51, 0x54, 0x68, 0xae,
+    0x0b, 0x8c, 0x47, 0xa2, 0x88, 0x85, 0x2a, 0x89, 0xad, 0xd3, 0x16, 0x5b,
+    0x20, 0x02, 0x4f, 0xc0, 0x04, 0x8e, 0x38, 0xde, 0xd8, 0x95, 0xfc, 0x97,
+    0xd9, 0xd2, 0x15, 0xdb, 0x1a, 0xcc, 0x69, 0x02, 0xad, 0x4a, 0x5a, 0x70,
+    0x8b, 0xbf, 0xfc, 0x35, 0x6d, 0x3a, 0x0f, 0xc9, 0xea, 0x78, 0x1a, 0xd1,
+    0xcb, 0xb7, 0xaa, 0xb8, 0xf2, 0x44, 0xdf, 0xb3, 0xfe, 0x24, 0x83, 0xb9,
+    0x53, 0x94, 0x7e, 0xa5, 0xc5, 0x3f, 0xa2, 0x31, 0x3d, 0xdc, 0x0b, 0xb1,
+    0x24, 0x2f, 0x99, 0x4a, 0xd4, 0x0e, 0x6b, 0x3a, 0x34, 0x31, 0xc5, 0x87,
+    0x68, 0xbd, 0x61, 0xbd, 0xe2, 0xa0, 0xdb, 0x9a, 0x33, 0xfd, 0xc5, 0x10,
+    0x3f, 0xfb, 0xeb, 0xbd, 0x29, 0x03, 0x85, 0x8d, 0x08, 0x7b, 0xb6, 0xf7,
+    0xf0, 0xf5, 0x13, 0x69, 0x3e, 0x35, 0x68, 0x58, 0x50, 0xdb, 0x50, 0x13,
+    0x02, 0x3e, 0x81, 0x4b, 0x44, 0x6c, 0x75, 0x02, 0xe6, 0x90, 0x75, 0x6c,
+    0xc6, 0x7c, 0x23, 0xec, 0x58, 0xfe, 0xbd, 0x15, 0x97, 0xe8, 0x29, 0x9f,
+    0x80, 0x54, 0x65, 0xb8, 0x3c, 0x40, 0xe6, 0xdb, 0xbe, 0x51, 0x73, 0xe5,
+    0xf1, 0x23, 0x02, 0x51, 0x1c, 0xce, 0x79, 0x2b, 0x8b, 0xa5, 0x6e, 0xcf,
+    0xaf, 0x58, 0xc5, 0xb5, 0xae, 0xb7, 0x1f, 0x42, 0x9a, 0x02, 0x4b, 0x2b,
+    0x73, 0xa7, 0xb7, 0xe8, 0x18, 0xf3, 0x86, 0x64, 0x44, 0x6e, 0xad, 0x8a,
+    0x00, 0x30, 0x15, 0x03, 0x0c, 0x66, 0xbf, 0xe4, 0xf7, 0x69, 0x68, 0x46,
+    0x60, 0x76, 0xc7, 0xa5, 0x1f, 0x4a, 0x09, 0x80, 0x2e, 0x45, 0xe9, 0xe5,
+    0x25, 0xb8, 0x4b, 0x7c, 0xe6, 0x45, 0x15, 0x55, 0xa0, 0x17, 0xc2, 0x69,
+    0x42, 0xb8, 0x48, 0x4b, 0x79, 0xc2, 0x37, 0x8f, 0x40, 0xc6, 0x40, 0x01,
+    0x81, 0x96, 0x9b, 0x17, 0x30, 0x3c, 0x89, 0xb1, 0xbf, 0xf3, 0xf1, 0xa5,
+    0x4b, 0x04, 0x6c, 0x1a, 0x8a, 0xa3, 0x45, 0x70, 0x5c, 0x62, 0x3d, 0x14,
+    0x44, 0x29, 0x54, 0x4d, 0x6e, 0x98, 0xb2, 0xd9, 0x00, 0x12, 0x7e, 0x00,
+    0x24, 0x71, 0xc6, 0xf6, 0xc4, 0xaf, 0xe4, 0xbe, 0xce, 0x90, 0xae, 0xd8,
+    0xd6, 0x63, 0x48, 0x15, 0x6a, 0x52, 0xd3, 0x84, 0x5d, 0xff, 0xe1, 0xab,
+    0x69, 0xd0, 0x7e, 0x4f, 0x53, 0xc0, 0xd6, 0x8e, 0x5d, 0xbd, 0x55, 0xc7,
+    0x92, 0x26, 0xfd, 0x9f, 0xf1, 0x24, 0x1d, 0xca, 0x9c, 0xa3, 0xf5, 0x2e,
+    0x29, 0xfd, 0x11, 0x89, 0xee, 0xe0, 0x5d, 0x89, 0x21, 0x7c, 0xca, 0x56,
+    0xa0, 0x73, 0x59, 0xd1, 0xa1, 0x8e, 0x2c, 0x3b, 0x45, 0xeb, 0x0d, 0xef,
+    0x15, 0x06, 0xdc, 0xd1, 0x9f, 0xee, 0x28, 0x81, 0xff, 0xdf, 0x5d, 0xe9,
+    0x48, 0x1c, 0x2c, 0x68, 0x43, 0xdd, 0xb7, 0xbf, 0x87, 0xa8, 0x9b, 0x49,
+    0xf1, 0xab, 0x42, 0xc2, 0x86, 0xda, 0x80, 0x98, 0x11, 0xf4, 0x0a, 0x5a,
+    0x23, 0x63, 0xa8, 0x17, 0x34, 0x83, 0xab, 0x66, 0x33, 0xe1, 0x1f, 0x62,
+    0xc7, 0xf5, 0xe8, 0xac, 0xbf, 0x41, 0x4c, 0xfc, 0x02, 0xa3, 0x2d, 0xc1,
+    0xe2, 0x07, 0x36, 0xdd, 0xf2, 0x8b, 0x9f, 0x2f, 0x89, 0x18, 0x12, 0x88,
+    0xe6, 0x73, 0xc9, 0x5c, 0x5d, 0x2b, 0x76, 0x7d, 0x7a, 0xc6, 0x2d, 0xad,
+    0x75, 0xb8, 0xfa, 0x14, 0xd0, 0x12, 0x59, 0x5b, 0x9d, 0x3d, 0xbf, 0x40,
+    0xc7, 0x9c, 0x33, 0x22, 0x23, 0x75, 0x6c, 0x50, 0x01, 0x80, 0xa8, 0x83,
+    0x06, 0xd4, 0xd6, 0x8d, 0x36, 0x78, 0xf9, 0x03, 0x23, 0xdb, 0x17, 0x90,
+    0x52, 0x0c, 0x5f, 0x1b, 0xe6, 0x44, 0x79, 0x52, 0xc5, 0x50, 0x17, 0x81,
+    0xf3, 0x1b, 0x88, 0xba, 0xfd, 0xbd, 0xa5, 0x51, 0x65, 0x6d, 0x33, 0x96,
+    0xc2, 0x71, 0x8d, 0x53, 0x1b, 0xab, 0xe9, 0xb9, 0xd0, 0x45, 0x61, 0xaf,
+    0xf9, 0xb7, 0x38, 0x55, 0x4f, 0xe9, 0x85, 0x1d, 0x4c, 0x0e, 0x40, 0x77,
+    0x03, 0xbc, 0x09, 0xd0, 0x37, 0xe3, 0xde, 0xf1, 0x0c, 0xa6, 0xc8, 0xd5,
+    0x63, 0x01, 0xfd, 0xe7, 0xc0, 0x9a, 0xe0, 0x98, 0x02, 0xe4, 0x5e, 0x9e,
+    0x52, 0x5b, 0x84, 0xb7, 0xce, 0x64, 0x51, 0x55, 0x5a, 0x01, 0x7c, 0x26,
+    0x94, 0x2b, 0x84, 0x84, 0xb7, 0x9c, 0x23, 0x78, 0xf4, 0x0c, 0x64, 0x00,
+    0x18, 0x19, 0x69, 0xb1, 0x73, 0x03, 0xc8, 0x9b, 0x1b, 0xff, 0x3f, 0x1a,
+    0x54, 0xb0, 0x46, 0xc1, 0xa8, 0xaa, 0x34, 0x57, 0x07, 0x13, 0xd3, 0x43,
+    0xb1, 0xaa, 0x4b, 0xc4, 0xcb, 0x5a, 0x9b, 0xa2, 0x23, 0x98, 0xa2, 0xd3,
+    0x2b, 0x8c, 0x7b, 0xf8, 0xc7, 0xaa, 0xf6, 0xcc, 0xb8, 0xfc, 0xb5, 0x77,
+    0xce, 0xff, 0x9d, 0x0e, 0xdb, 0x2b, 0x03, 0xc7, 0x42, 0x86, 0xf1, 0xcb,
+    0xa2, 0xa7, 0x85, 0x77, 0x58, 0x1a, 0x8f, 0x8c, 0xb4, 0x16, 0xf7, 0xe0,
+    0xe9, 0x8e, 0x54, 0x42, 0x2a, 0x1e, 0x10, 0xf6, 0xbc, 0x1a, 0x9f, 0xa1,
+    0xcb, 0xff, 0x13, 0x06, 0x88, 0x6b, 0xb1, 0xeb, 0x37, 0x26, 0xe5, 0x34,
+    0x0d, 0x73, 0x87, 0x91, 0x60, 0x6c, 0xd7, 0x2d, 0xc3, 0x5f, 0x40, 0x68,
+    0x45, 0x07, 0x6e, 0x62, 0xa9, 0xe3, 0x52, 0x75, 0xef, 0x14, 0xf5, 0x89,
+    0x0a, 0x3a, 0x57, 0x8b, 0xac, 0xbe, 0x86, 0x67, 0xd1, 0xd8, 0x35, 0xe5,
+    0xe7, 0x75, 0xb8, 0xf8, 0x28, 0x6d, 0xa8, 0x09, 0x81, 0x1f, 0x40, 0xa5,
+    0xa2, 0x36, 0x3a, 0x81, 0x73, 0x48, 0x3e, 0x8c, 0x9d, 0x1f, 0x78, 0xc5,
+    0x92, 0x36, 0x1a, 0xae, 0xdf, 0xda, 0xf8, 0x0a, 0x7e, 0x69, 0xcb, 0xaf,
+    0x74, 0x59, 0x49, 0x72, 0xa7, 0x97, 0x1c, 0x8c, 0xf0, 0x16, 0x01, 0x4a,
+    0xcc, 0x1a, 0xa1, 0x24, 0x83, 0x7b, 0x34, 0x65, 0x20, 0x51, 0x11, 0xae,
+    0x5d, 0xa7, 0x68, 0x9c, 0xec, 0x29, 0x27, 0xfc, 0x07, 0x49, 0xb4, 0x9b,
+    0x65, 0xb2, 0x51, 0x97, 0xae, 0xa5, 0x8a, 0x70, 0xe5, 0x53, 0xd3, 0xa2,
+    0x34, 0x35, 0xbd, 0xbf, 0x75, 0x64, 0xda, 0x88, 0x8c, 0xe9, 0xc3, 0x9a,
+    0x32, 0xf0, 0x5a, 0x96, 0xae, 0xef, 0x9a, 0xdd, 0x84, 0xc2, 0x97, 0x22,
+    0x2f, 0x06, 0x83, 0x32, 0x10, 0xff, 0x1d, 0x61, 0x60, 0x5f, 0x69, 0x10,
+    0x5d, 0x23, 0xc6, 0xf3, 0x3f, 0xa9, 0x53, 0xfe, 0xd0, 0x3e, 0x90, 0xe6,
+    0x54, 0x48, 0xab, 0x01, 0x76, 0x75, 0x88, 0x7b, 0x4e, 0xc6, 0xd0, 0x9b,
+    0x7a, 0xcd, 0x87, 0x36, 0x3e, 0x7e, 0x3d, 0xef, 0x10, 0xca, 0x6c, 0x8d,
+    0x56, 0x30, 0x1f, 0xde, 0x7c, 0x09, 0xae, 0x09, 0x80, 0x2e, 0x45, 0xe9,
+    0xe5, 0x25, 0xb8, 0x4b, 0x7c, 0xe6, 0x45, 0x15, 0x55, 0xa0, 0x17, 0xc2,
+    0x69, 0x42, 0xb8, 0x48, 0x4b, 0x79, 0xc2, 0x37, 0x8f, 0x40, 0xc6, 0x40,
+    0x01, 0x81, 0x96, 0x9b, 0x17, 0x30, 0x3c, 0x89, 0xb1, 0xbf, 0xf3, 0xf1,
+    0xa5, 0x5c, 0xdc, 0x1e, 0x69, 0xfc, 0xf1, 0xd8, 0x5d, 0xda, 0x13, 0x5b,
+    0xbc, 0x1f, 0x41, 0x4a, 0xde, 0x44, 0x3c, 0x5e, 0xbd, 0x46, 0xb7, 0xad,
+    0x32, 0xb8, 0xc7, 0xbf, 0x8c, 0x7a, 0xaf, 0x6c, 0xcb, 0x8f, 0xcb, 0x57,
+    0x7c, 0xef, 0xf9, 0xd0, 0xed, 0xb2, 0xb0, 0x3c, 0x74, 0x28, 0x6f, 0x1c,
+    0xba, 0x2a, 0x78, 0x57, 0x75, 0x81, 0xa8, 0xf8, 0xcb, 0x41, 0x6f, 0x7e,
+    0x0e, 0x98, 0xe5, 0x44, 0x22, 0xa2, 0x00, 0x6c, 0xba, 0xaf, 0x51, 0xcc,
+    0x9f, 0xba, 0x97, 0x39, 0xbb, 0x41, 0x60, 0xf0, 0xe9, 0xb7, 0xa7, 0xa0,
+    0x7b, 0x7a, 0xde, 0xc9, 0x22, 0x13, 0xf4, 0x04, 0xaf, 0x91, 0xf5, 0x37,
+    0x53, 0xad, 0x8d, 0x0d, 0x15, 0x7a, 0xf1, 0x81, 0x07, 0xd6, 0xa8, 0x80,
+    0x0c, 0x8d, 0x02, 0x79, 0x43, 0x50, 0x98, 0x27, 0xfc, 0xbc, 0xb7, 0x8f,
+    0xe0, 0xe6, 0x46, 0x6f, 0x25, 0xef, 0x2a, 0x04, 0xd1, 0xbe, 0x10, 0x3d,
+    0xb4, 0x43, 0x3e, 0xf7, 0xea, 0xf4, 0xb8, 0x24, 0xdc, 0x77, 0x4f, 0x52,
+    0x26, 0x55, 0xae, 0xbc, 0x6f, 0xe0, 0x8e, 0x41, 0x97, 0x82, 0xd4, 0xb5,
+    0x77, 0x7c, 0xd6, 0xec, 0x26, 0x14, 0xb9, 0x11, 0x78, 0x34, 0x19, 0x90,
+    0x87, 0xf8, 0xeb, 0x0b, 0x02, 0xfb, 0x48, 0x82, 0xe9, 0x1e, 0x37, 0x99,
+    0xfd, 0x4a, 0x9f, 0xf6, 0x81, 0xf4, 0x87, 0x32, 0xa2, 0x45, 0x58, 0x0b,
+    0xb3, 0xac, 0x43, 0xda, 0x76, 0x36, 0x84, 0xdb, 0xd6, 0x6c, 0x39, 0xb1,
+    0xf3, 0xf1, 0xef, 0x78, 0x86, 0x53, 0x64, 0x6a, 0xb1, 0x80, 0xfe, 0xf3,
+    0xe0, 0x4d, 0x70, 0x4c, 0x01, 0x72, 0x2f, 0x4f, 0x29, 0x2d, 0xc2, 0x5c,
+};
+static_assert(sizeof(kBytesTestReadSymbol16) == kNumBytesTestReadSymbol16, "");
diff --git a/src/utils/memory_test.cc b/src/utils/memory_test.cc
new file mode 100644
index 0000000..42f6a15
--- /dev/null
+++ b/src/utils/memory_test.cc
@@ -0,0 +1,184 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/memory.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+
+#include "absl/base/config.h"
+#include "gtest/gtest.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+#include <exception>
+#endif
+
+namespace libgav1 {
+namespace {
+
+constexpr size_t kMaxAllocableSize = 0x40000000;
+
+struct Small : public Allocable {
+  uint8_t x;
+};
+
+struct Huge : public Allocable {
+  uint8_t x[kMaxAllocableSize + 1];
+};
+
+struct SmallMaxAligned : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x;
+};
+
+struct HugeMaxAligned : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1];
+};
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+struct ThrowingConstructor : public Allocable {
+  ThrowingConstructor() { throw std::exception(); }
+
+  uint8_t x;
+};
+
+struct MaxAlignedThrowingConstructor : public MaxAlignedAllocable {
+  MaxAlignedThrowingConstructor() { throw std::exception(); }
+
+  uint8_t x;
+};
+#endif
+
+TEST(MemoryTest, TestAlignedAllocFree) {
+  for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
+    void* p = AlignedAlloc(alignment, 1);
+    // Note this additional check is to avoid an incorrect static-analysis
+    // warning for leaked memory with a plain ASSERT_NE().
+    if (p == nullptr) {
+      FAIL() << "AlignedAlloc(" << alignment << ", 1)";
+    }
+    const auto p_value = reinterpret_cast<uintptr_t>(p);
+    EXPECT_EQ(p_value % alignment, 0)
+        << "AlignedAlloc(" << alignment << ", 1) = " << p;
+    AlignedFree(p);
+  }
+}
+
+TEST(MemoryTest, TestAlignedUniquePtrAlloc) {
+  for (size_t alignment = 1; alignment <= 1 << 20; alignment <<= 1) {
+    auto p = MakeAlignedUniquePtr<uint8_t>(alignment, 1);
+    ASSERT_NE(p, nullptr) << "MakeAlignedUniquePtr(" << alignment << ", 1)";
+    const auto p_value = reinterpret_cast<uintptr_t>(p.get());
+    EXPECT_EQ(p_value % alignment, 0)
+        << "MakeAlignedUniquePtr(" << alignment << ", 1) = " << p.get();
+  }
+}
+
+TEST(MemoryTest, TestAllocable) {
+  // Allocable::operator new (std::nothrow) is called.
+  std::unique_ptr<Small> small(new (std::nothrow) Small);
+  EXPECT_NE(small, nullptr);
+  // Allocable::operator delete is called.
+  small = nullptr;
+
+  // Allocable::operator new[] (std::nothrow) is called.
+  std::unique_ptr<Small[]> small_array_of_smalls(new (std::nothrow) Small[10]);
+  EXPECT_NE(small_array_of_smalls, nullptr);
+  // Allocable::operator delete[] is called.
+  small_array_of_smalls = nullptr;
+
+  // Allocable::operator new (std::nothrow) is called.
+  std::unique_ptr<Huge> huge(new (std::nothrow) Huge);
+  EXPECT_EQ(huge, nullptr);
+
+  // Allocable::operator new[] (std::nothrow) is called.
+  std::unique_ptr<Small[]> huge_array_of_smalls(
+      new (std::nothrow) Small[kMaxAllocableSize / sizeof(Small) + 1]);
+  EXPECT_EQ(huge_array_of_smalls, nullptr);
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+  try {
+    // Allocable::operator new (std::nothrow) is called.
+    // The constructor throws an exception.
+    // Allocable::operator delete (std::nothrow) is called.
+    ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor;
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  try {
+    // Allocable::operator new[] (std::nothrow) is called.
+    // The constructor throws an exception.
+    // Allocable::operator delete[] (std::nothrow) is called.
+    ThrowingConstructor* always = new (std::nothrow) ThrowingConstructor[2];
+    static_cast<void>(always);
+  } catch (...) {
+  }
+#endif  // ABSL_HAVE_EXCEPTIONS
+}
+
+TEST(MemoryTest, TestMaxAlignedAllocable) {
+  // MaxAlignedAllocable::operator new (std::nothrow) is called.
+  std::unique_ptr<SmallMaxAligned> small(new (std::nothrow) SmallMaxAligned);
+  EXPECT_NE(small, nullptr);
+  // Note this check doesn't guarantee conformance as a suitably aligned
+  // address may be returned from any allocator.
+  EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1), 0);
+  // MaxAlignedAllocable::operator delete is called.
+  small = nullptr;
+
+  // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+  std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
+      new (std::nothrow) SmallMaxAligned[10]);
+  EXPECT_NE(small_array_of_smalls, nullptr);
+  EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
+                (kMaxAlignment - 1),
+            0);
+  // MaxAlignedAllocable::operator delete[] is called.
+  small_array_of_smalls = nullptr;
+
+  // MaxAlignedAllocable::operator new (std::nothrow) is called.
+  std::unique_ptr<HugeMaxAligned> huge(new (std::nothrow) HugeMaxAligned);
+  EXPECT_EQ(huge, nullptr);
+
+  // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+  std::unique_ptr<SmallMaxAligned[]> huge_array_of_smalls(
+      new (std::nothrow)
+          SmallMaxAligned[kMaxAllocableSize / sizeof(SmallMaxAligned) + 1]);
+  EXPECT_EQ(huge_array_of_smalls, nullptr);
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+  try {
+    // MaxAlignedAllocable::operator new (std::nothrow) is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete (std::nothrow) is called.
+    auto* always = new (std::nothrow) MaxAlignedThrowingConstructor;
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  try {
+    // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete[] (std::nothrow) is called.
+    auto* always = new (std::nothrow) MaxAlignedThrowingConstructor[2];
+    static_cast<void>(always);
+  } catch (...) {
+  }
+#endif  // ABSL_HAVE_EXCEPTIONS
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/queue_test.cc b/src/utils/queue_test.cc
new file mode 100644
index 0000000..d84ae5f
--- /dev/null
+++ b/src/utils/queue_test.cc
@@ -0,0 +1,86 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/queue.h"
+
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+struct TestClass {
+  TestClass() = default;
+  explicit TestClass(int i) : i(i) {}
+  int i;
+  // The vector exists simply so that the class is not trivially copyable.
+  std::vector<int> dummy;
+};
+
+TEST(QueueTest, Basic) {
+  Queue<TestClass> queue;
+  ASSERT_TRUE(queue.Init(8));
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_FALSE(queue.Full());
+    TestClass test(i);
+    queue.Push(std::move(test));
+    EXPECT_EQ(queue.Back().i, i);
+    EXPECT_FALSE(queue.Empty());
+  }
+  EXPECT_TRUE(queue.Full());
+
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_FALSE(queue.Empty());
+    EXPECT_EQ(queue.Front().i, i);
+    queue.Pop();
+    EXPECT_FALSE(queue.Full());
+  }
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_FALSE(queue.Full());
+    TestClass test(i);
+    queue.Push(std::move(test));
+    EXPECT_EQ(queue.Back().i, i);
+    EXPECT_FALSE(queue.Empty());
+  }
+  EXPECT_TRUE(queue.Full());
+  queue.Clear();
+  EXPECT_TRUE(queue.Empty());
+  EXPECT_FALSE(queue.Full());
+}
+
+TEST(QueueTest, WrapAround) {
+  Queue<TestClass> queue;
+  ASSERT_TRUE(queue.Init(8));
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 100; ++i) {
+    EXPECT_FALSE(queue.Full());
+    TestClass test(i);
+    queue.Push(std::move(test));
+    EXPECT_EQ(queue.Back().i, i);
+    EXPECT_FALSE(queue.Empty());
+    EXPECT_EQ(queue.Front().i, i);
+    queue.Pop();
+    EXPECT_TRUE(queue.Empty());
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/raw_bit_reader_test.cc b/src/utils/raw_bit_reader_test.cc
new file mode 100644
index 0000000..22a97a7
--- /dev/null
+++ b/src/utils/raw_bit_reader_test.cc
@@ -0,0 +1,580 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/raw_bit_reader.h"
+
+#include <bitset>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "src/utils/constants.h"
+#include "tests/third_party/libvpx/acm_random.h"
+
+namespace libgav1 {
+namespace {
+
+std::string IntegerToString(int x) { return std::bitset<8>(x).to_string(); }
+
+class RawBitReaderTest : public testing::TestWithParam<std::tuple<int, int>> {
+ protected:
+  RawBitReaderTest()
+      : literal_size_(std::get<0>(GetParam())),
+        test_data_size_(std::get<1>(GetParam())) {}
+
+  void CreateReader(const std::vector<uint8_t>& data) {
+    data_ = data;
+    raw_bit_reader_.reset(new (std::nothrow)
+                              RawBitReader(data_.data(), data_.size()));
+  }
+
+  void CreateReader(int size) {
+    libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+    data_.clear();
+    for (int i = 0; i < size; ++i) {
+      data_.push_back(rnd.Rand8());
+    }
+    raw_bit_reader_.reset(new (std::nothrow)
+                              RawBitReader(data_.data(), data_.size()));
+  }
+
+  // Some tests don't depend on |literal_size_|. For those tests, return true if
+  // the |literal_size_| is greater than 1. If this function returns true, the
+  // test will abort.
+  bool RunOnlyOnce() const { return literal_size_ > 1; }
+
+  std::unique_ptr<RawBitReader> raw_bit_reader_;
+  std::vector<uint8_t> data_;
+  int literal_size_;
+  int test_data_size_;
+};
+
+TEST_P(RawBitReaderTest, ReadBit) {
+  if (RunOnlyOnce()) return;
+  CreateReader(test_data_size_);
+  for (const auto& value : data_) {
+    const std::string expected = IntegerToString(value);
+    for (int j = 0; j < 8; ++j) {
+      EXPECT_FALSE(raw_bit_reader_->Finished());
+      EXPECT_EQ(static_cast<int>(expected[j] == '1'),
+                raw_bit_reader_->ReadBit());
+    }
+  }
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_EQ(raw_bit_reader_->ReadBit(), -1);
+}
+
+TEST_P(RawBitReaderTest, ReadLiteral) {
+  const int size_bytes = literal_size_;
+  const int size_bits = 8 * size_bytes;
+  CreateReader(test_data_size_ * size_bytes);
+  for (size_t i = 0; i < data_.size(); i += size_bytes) {
+    uint32_t expected_literal = 0;
+    for (int j = 0; j < size_bytes; ++j) {
+      expected_literal |=
+          static_cast<uint32_t>(data_[i + j] << (8 * (size_bytes - j - 1)));
+    }
+    EXPECT_FALSE(raw_bit_reader_->Finished());
+    const int64_t actual_literal = raw_bit_reader_->ReadLiteral(size_bits);
+    EXPECT_EQ(static_cast<int64_t>(expected_literal), actual_literal);
+    EXPECT_GE(actual_literal, 0);
+  }
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_EQ(raw_bit_reader_->ReadLiteral(10), -1);
+}
+
+TEST_P(RawBitReaderTest, ReadLiteral32BitsWithMsbSet) {
+  if (RunOnlyOnce()) return;
+  // Three 32-bit values with MSB set.
+  CreateReader({0xff, 0xff, 0xff, 0xff,    // 4294967295
+                0x80, 0xff, 0xee, 0xdd,    // 2164256477
+                0xa0, 0xaa, 0xbb, 0xcc});  // 2695543756
+  static constexpr int64_t expected_literals[] = {4294967295, 2164256477,
+                                                  2695543756};
+  for (const int64_t expected_literal : expected_literals) {
+    EXPECT_FALSE(raw_bit_reader_->Finished());
+    const int64_t actual_literal = raw_bit_reader_->ReadLiteral(32);
+    EXPECT_EQ(expected_literal, actual_literal);
+    EXPECT_GE(actual_literal, 0);
+  }
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_EQ(raw_bit_reader_->ReadLiteral(10), -1);
+}
+
+TEST_P(RawBitReaderTest, ReadLiteralNotEnoughBits) {
+  if (RunOnlyOnce()) return;
+  CreateReader(4);  // 32 bits.
+  EXPECT_GE(raw_bit_reader_->ReadLiteral(16), 0);
+  EXPECT_EQ(raw_bit_reader_->ReadLiteral(32), -1);
+}
+
+TEST_P(RawBitReaderTest, ReadLiteralMaxNumBits) {
+  if (RunOnlyOnce()) return;
+  CreateReader(4);  // 32 bits.
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(32), -1);
+}
+
+TEST_P(RawBitReaderTest, ReadInverseSignedLiteral) {
+  if (RunOnlyOnce()) return;
+  // This is the only usage for this function in the decoding process. So
+  // testing just that case.
+  const int size_bits = 6;
+  data_.clear();
+  // Negative value followed by a positive value.
+  data_.push_back(0xd2);
+  data_.push_back(0xa4);
+  raw_bit_reader_.reset(new (std::nothrow)
+                            RawBitReader(data_.data(), data_.size()));
+  int value;
+  EXPECT_TRUE(raw_bit_reader_->ReadInverseSignedLiteral(size_bits, &value));
+  EXPECT_EQ(value, -23);
+  EXPECT_TRUE(raw_bit_reader_->ReadInverseSignedLiteral(size_bits, &value));
+  EXPECT_EQ(value, 41);
+  // We have only two bits left. Trying to read an inverse signed literal of 2
+  // bits actually needs 3 bits. So this should fail.
+  EXPECT_FALSE(raw_bit_reader_->ReadInverseSignedLiteral(2, &value));
+}
+
+TEST_P(RawBitReaderTest, ZeroSize) {
+  if (RunOnlyOnce()) return;
+  // Valid data, zero size.
+  data_.clear();
+  data_.push_back(0xf0);
+  raw_bit_reader_.reset(new (std::nothrow) RawBitReader(data_.data(), 0));
+  EXPECT_EQ(raw_bit_reader_->ReadBit(), -1);
+  EXPECT_EQ(raw_bit_reader_->ReadLiteral(2), -1);
+  // NULL data, zero size.
+  raw_bit_reader_.reset(new (std::nothrow) RawBitReader(nullptr, 0));
+  EXPECT_EQ(raw_bit_reader_->ReadBit(), -1);
+  EXPECT_EQ(raw_bit_reader_->ReadLiteral(2), -1);
+}
+
+TEST_P(RawBitReaderTest, AlignToNextByte) {
+  if (RunOnlyOnce()) return;
+  CreateReader({0x00, 0x00, 0x00, 0x0f});
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 0);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 0);
+  EXPECT_TRUE(raw_bit_reader_->AlignToNextByte());
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 0);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 0);
+  EXPECT_NE(raw_bit_reader_->ReadBit(), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 1);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 1);
+  EXPECT_TRUE(raw_bit_reader_->AlignToNextByte());
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 1);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(16), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 24);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 3);
+  EXPECT_TRUE(raw_bit_reader_->AlignToNextByte());
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 24);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 3);
+  EXPECT_NE(raw_bit_reader_->ReadBit(), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 25);
+  EXPECT_EQ(raw_bit_reader_->byte_offset(), 4);
+  // Some bits are non-zero.
+  EXPECT_FALSE(raw_bit_reader_->AlignToNextByte());
+}
+
+TEST_P(RawBitReaderTest, VerifyAndSkipTrailingBits) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data;
+
+  // 1 byte trailing byte.
+  data.push_back(0x80);
+  CreateReader(data);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 0);
+  EXPECT_TRUE(raw_bit_reader_->VerifyAndSkipTrailingBits(8));
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+
+  // 2 byte trailing byte beginning at a byte-aligned offset.
+  data.clear();
+  data.push_back(0xf8);
+  data.push_back(0x80);
+  CreateReader(data);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(8), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_TRUE(raw_bit_reader_->VerifyAndSkipTrailingBits(8));
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+
+  // 2 byte trailing byte beginning at a non-byte-aligned offset.
+  data.clear();
+  data.push_back(0xf8);
+  data.push_back(0x00);
+  CreateReader(data);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(4), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 4);
+  EXPECT_TRUE(raw_bit_reader_->VerifyAndSkipTrailingBits(4));
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+
+  // Invalid trailing byte at a byte-aligned offset.
+  data.clear();
+  data.push_back(0xf7);
+  data.push_back(0x70);
+  CreateReader(data);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(8), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_FALSE(raw_bit_reader_->VerifyAndSkipTrailingBits(8));
+
+  // Invalid trailing byte at a non-byte-aligned offset.
+  CreateReader(data);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(4), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 4);
+  EXPECT_FALSE(raw_bit_reader_->VerifyAndSkipTrailingBits(12));
+
+  // No more data available.
+  CreateReader(data);
+  EXPECT_NE(raw_bit_reader_->ReadLiteral(16), -1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_FALSE(raw_bit_reader_->VerifyAndSkipTrailingBits(8));
+}
+
+TEST_P(RawBitReaderTest, ReadLittleEndian) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data;
+  size_t actual;
+
+  // Invalid input.
+  data.push_back(0x00);  // dummy.
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadLittleEndian(1, nullptr));
+
+  // One byte value.
+  data.clear();
+  data.push_back(0x01);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadLittleEndian(1, &actual));
+  EXPECT_EQ(actual, 1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // One byte value with leading bytes.
+  data.clear();
+  data.push_back(0x01);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadLittleEndian(4, &actual));
+  EXPECT_EQ(actual, 1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 32);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Two byte value.
+  data.clear();
+  data.push_back(0xD9);
+  data.push_back(0x01);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadLittleEndian(2, &actual));
+  EXPECT_EQ(actual, 473);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Two byte value with leading bytes.
+  data.clear();
+  data.push_back(0xD9);
+  data.push_back(0x01);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadLittleEndian(4, &actual));
+  EXPECT_EQ(actual, 473);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 32);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Not enough bytes.
+  data.clear();
+  data.push_back(0x01);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadLittleEndian(2, &actual));
+}
+
+TEST_P(RawBitReaderTest, ReadUnsignedLeb128) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data;
+  size_t actual;
+
+  // Invalid input.
+  data.push_back(0x00);  // dummy.
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUnsignedLeb128(nullptr));
+
+  // One byte value.
+  data.clear();
+  data.push_back(0x01);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+  EXPECT_EQ(actual, 1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // One byte value with trailing bytes.
+  data.clear();
+  data.push_back(0x81);
+  data.push_back(0x80);
+  data.push_back(0x80);
+  data.push_back(0x00);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+  EXPECT_EQ(actual, 1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 32);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Two byte value.
+  data.clear();
+  data.push_back(0xD9);
+  data.push_back(0x01);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+  EXPECT_EQ(actual, 217);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Two byte value with trailing bytes.
+  data.clear();
+  data.push_back(0xD9);
+  data.push_back(0x81);
+  data.push_back(0x80);
+  data.push_back(0x80);
+  data.push_back(0x00);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+  EXPECT_EQ(actual, 217);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 40);
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+
+  // Value > 32 bits.
+  data.clear();
+  for (int i = 0; i < 5; ++i) data.push_back(0xD9);
+  data.push_back(0x00);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+
+  // Not enough bytes (truncated leb128 value).
+  data.clear();
+  data.push_back(0x81);
+  data.push_back(0x81);
+  data.push_back(0x81);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+
+  // Exceeds kMaximumLeb128Size.
+  data.clear();
+  for (int i = 0; i < 10; ++i) data.push_back(0x80);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUnsignedLeb128(&actual));
+}
+
+TEST_P(RawBitReaderTest, ReadUvlc) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data;
+  uint32_t actual;
+
+  // Invalid input.
+  data.push_back(0x00);  // dummy.
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUvlc(nullptr));
+
+  // Zero bit value.
+  data.clear();
+  data.push_back(0x80);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUvlc(&actual));
+  EXPECT_EQ(actual, 0);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 1);
+
+  // One bit value.
+  data.clear();
+  data.push_back(0x60);  // 011...
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUvlc(&actual));
+  EXPECT_EQ(actual, 2);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 3);
+
+  // Two bit value.
+  data.clear();
+  data.push_back(0x38);  // 00111...
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUvlc(&actual));
+  EXPECT_EQ(actual, 6);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 5);
+
+  // 31 bit value.
+  data.clear();
+  // (1 << 32) - 2 (= UINT32_MAX - 1) is the largest value that can be encoded
+  // as uvlc().
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x01);
+  data.push_back(0xFF);
+  data.push_back(0xFF);
+  data.push_back(0xFF);
+  data.push_back(0xFE);
+  CreateReader(data);
+  ASSERT_TRUE(raw_bit_reader_->ReadUvlc(&actual));
+  EXPECT_EQ(actual, UINT32_MAX - 1);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 63);
+
+  // Not enough bits (truncated uvlc value).
+  data.clear();
+  data.push_back(0x07);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUvlc(&actual));
+
+  // 32 bits.
+  data.clear();
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0xFF);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUvlc(&actual));
+
+  // Exceeds 32 bits.
+  data.clear();
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x00);
+  data.push_back(0x0F);
+  CreateReader(data);
+  EXPECT_FALSE(raw_bit_reader_->ReadUvlc(&actual));
+}
+
+TEST_P(RawBitReaderTest, DecodeSignedSubexpWithReference) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data;
+  int actual;
+
+  data.push_back(0xa0);  // v = 5;
+  CreateReader(data);
+  EXPECT_TRUE(raw_bit_reader_->DecodeSignedSubexpWithReference(
+      10, 20, 15, kGlobalMotionReadControl, &actual));
+  EXPECT_EQ(actual, 12);
+
+  data.clear();
+  data.push_back(0xd0);  // v = 6; extra_bit = 1;
+  CreateReader(data);
+  EXPECT_TRUE(raw_bit_reader_->DecodeSignedSubexpWithReference(
+      10, 20, 15, kGlobalMotionReadControl, &actual));
+  EXPECT_EQ(actual, 11);
+
+  data.clear();
+  data.push_back(0xc8);  // subexp_more_bits = 1; v = 9;
+  CreateReader(data);
+  EXPECT_TRUE(raw_bit_reader_->DecodeSignedSubexpWithReference(
+      10, 40, 15, kGlobalMotionReadControl, &actual));
+  EXPECT_EQ(actual, 27);
+
+  data.clear();
+  data.push_back(0x60);  // subexp_more_bits = 0; subexp_bits = 6.
+  CreateReader(data);
+  EXPECT_TRUE(raw_bit_reader_->DecodeSignedSubexpWithReference(
+      10, 40, 15, kGlobalMotionReadControl, &actual));
+  EXPECT_EQ(actual, 18);
+
+  data.clear();
+  data.push_back(0x60);
+  CreateReader(data);
+  // Control is greater than 32, which makes b >= 32 in DecodeSubexp() and
+  // should return false.
+  EXPECT_FALSE(raw_bit_reader_->DecodeSignedSubexpWithReference(10, 40, 15, 35,
+                                                                &actual));
+}
+
+TEST_P(RawBitReaderTest, DecodeUniform) {
+  if (RunOnlyOnce()) return;
+  // Test the example from the AV1 spec, Section 4.10.7. ns(n).
+  // n = 5
+  // Value            ns(n) encoding
+  // -------------------------------
+  // 0                 00
+  // 1                 01
+  // 2                 10
+  // 3                110
+  // 4                111
+  //
+  // The five encoded values are concatenated into two bytes.
+  std::vector<uint8_t> data = {0x1b, 0x70};
+  CreateReader(data);
+  int actual;
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_TRUE(raw_bit_reader_->DecodeUniform(5, &actual));
+    EXPECT_EQ(actual, i);
+  }
+
+  // If n is a power of 2, ns(n) is simply the log2(n)-bit representation of
+  // the unsigned number.
+  // Test n = 16.
+  // The 16 encoded values are concatenated into 8 bytes.
+  data = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+  CreateReader(data);
+  for (int i = 0; i < 16; ++i) {
+    EXPECT_TRUE(raw_bit_reader_->DecodeUniform(16, &actual));
+    EXPECT_EQ(actual, i);
+  }
+}
+
+TEST_P(RawBitReaderTest, SkipBytes) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data = {0x00, 0x00, 0x00, 0x00, 0x00};
+  CreateReader(data);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 0);
+  EXPECT_TRUE(raw_bit_reader_->SkipBytes(1));
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_GE(raw_bit_reader_->ReadBit(), 0);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 9);
+  EXPECT_FALSE(raw_bit_reader_->SkipBytes(1));  // Not at a byte boundary.
+  EXPECT_TRUE(raw_bit_reader_->AlignToNextByte());
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+  EXPECT_FALSE(raw_bit_reader_->SkipBytes(10));  // Not enough bytes.
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 16);
+  EXPECT_TRUE(raw_bit_reader_->SkipBytes(3));
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_EQ(raw_bit_reader_->ReadBit(), -1);
+}
+
+TEST_P(RawBitReaderTest, SkipBits) {
+  if (RunOnlyOnce()) return;
+  std::vector<uint8_t> data = {0x00, 0x00, 0x00, 0x00, 0x00};
+  CreateReader(data);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 0);
+  EXPECT_TRUE(raw_bit_reader_->SkipBits(8));
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 8);
+  EXPECT_GE(raw_bit_reader_->ReadBit(), 0);
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 9);
+  EXPECT_TRUE(raw_bit_reader_->SkipBits(10));  // Not at a byte boundary.
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 19);
+  EXPECT_FALSE(raw_bit_reader_->SkipBits(80));  // Not enough bytes.
+  EXPECT_EQ(raw_bit_reader_->bit_offset(), 19);
+  EXPECT_TRUE(raw_bit_reader_->SkipBits(21));
+  EXPECT_TRUE(raw_bit_reader_->Finished());
+  EXPECT_EQ(raw_bit_reader_->ReadBit(), -1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    RawBitReaderTestInstance, RawBitReaderTest,
+    testing::Combine(testing::Range(1, 5),    // literal size.
+                     testing::Values(100)));  // number of bits/literals.
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/segmentation_map_test.cc b/src/utils/segmentation_map_test.cc
new file mode 100644
index 0000000..4d8a7c9
--- /dev/null
+++ b/src/utils/segmentation_map_test.cc
@@ -0,0 +1,120 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/segmentation_map.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(SegmentationMapTest, Clear) {
+  constexpr int32_t kRows4x4 = 60;
+  constexpr int32_t kColumns4x4 = 80;
+  SegmentationMap segmentation_map;
+  ASSERT_TRUE(segmentation_map.Allocate(kRows4x4, kColumns4x4));
+
+  segmentation_map.Clear();
+  for (int row4x4 = 0; row4x4 < kRows4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kColumns4x4; ++column4x4) {
+      EXPECT_EQ(segmentation_map.segment_id(row4x4, column4x4), 0);
+    }
+  }
+}
+
+TEST(SegmentationMapTest, FillBlock) {
+  constexpr int32_t kRows4x4 = 60;
+  constexpr int32_t kColumns4x4 = 80;
+  SegmentationMap segmentation_map;
+  ASSERT_TRUE(segmentation_map.Allocate(kRows4x4, kColumns4x4));
+
+  // Fill the whole image with 2.
+  segmentation_map.FillBlock(0, 0, kColumns4x4, kRows4x4, 2);
+  // Fill a block with 1.
+  constexpr int kBlockWidth4x4 = 10;
+  constexpr int kBlockHeight4x4 = 20;
+  segmentation_map.FillBlock(4, 6, kBlockWidth4x4, kBlockHeight4x4, 1);
+  for (int row4x4 = 0; row4x4 < kRows4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kColumns4x4; ++column4x4) {
+      if (4 <= row4x4 && row4x4 < 4 + kBlockHeight4x4 && 6 <= column4x4 &&
+          column4x4 < 6 + kBlockWidth4x4) {
+        // Inside the block.
+        EXPECT_EQ(segmentation_map.segment_id(row4x4, column4x4), 1);
+      } else {
+        // Outside the block.
+        EXPECT_EQ(segmentation_map.segment_id(row4x4, column4x4), 2);
+      }
+    }
+  }
+}
+
+TEST(SegmentationMapTest, CopyFrom) {
+  constexpr int32_t kRows4x4 = 60;
+  constexpr int32_t kColumns4x4 = 80;
+  SegmentationMap segmentation_map;
+  ASSERT_TRUE(segmentation_map.Allocate(kRows4x4, kColumns4x4));
+
+  // Split the segmentation map into four blocks of equal size.
+  constexpr int kBlockWidth4x4 = 40;
+  constexpr int kBlockHeight4x4 = 30;
+  segmentation_map.FillBlock(0, 0, kBlockWidth4x4, kBlockHeight4x4, 1);
+  segmentation_map.FillBlock(0, kBlockWidth4x4, kBlockWidth4x4, kBlockHeight4x4,
+                             2);
+  segmentation_map.FillBlock(kBlockHeight4x4, 0, kBlockWidth4x4,
+                             kBlockHeight4x4, 3);
+  segmentation_map.FillBlock(kBlockHeight4x4, kBlockWidth4x4, kBlockWidth4x4,
+                             kBlockHeight4x4, 4);
+
+  SegmentationMap segmentation_map2;
+  ASSERT_TRUE(segmentation_map2.Allocate(kRows4x4, kColumns4x4));
+  segmentation_map2.CopyFrom(segmentation_map);
+
+  for (int row4x4 = 0; row4x4 < kBlockHeight4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kBlockWidth4x4; ++column4x4) {
+      EXPECT_EQ(segmentation_map.segment_id(row4x4, column4x4), 1);
+      EXPECT_EQ(segmentation_map2.segment_id(row4x4, column4x4), 1);
+    }
+  }
+  for (int row4x4 = 0; row4x4 < kBlockHeight4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kBlockWidth4x4; ++column4x4) {
+      EXPECT_EQ(segmentation_map.segment_id(row4x4, kBlockWidth4x4 + column4x4),
+                2);
+      EXPECT_EQ(
+          segmentation_map2.segment_id(row4x4, kBlockWidth4x4 + column4x4), 2);
+    }
+  }
+  for (int row4x4 = 0; row4x4 < kBlockHeight4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kBlockWidth4x4; ++column4x4) {
+      EXPECT_EQ(
+          segmentation_map.segment_id(kBlockHeight4x4 + row4x4, column4x4), 3);
+      EXPECT_EQ(
+          segmentation_map2.segment_id(kBlockHeight4x4 + row4x4, column4x4), 3);
+    }
+  }
+  for (int row4x4 = 0; row4x4 < kBlockHeight4x4; ++row4x4) {
+    for (int column4x4 = 0; column4x4 < kBlockWidth4x4; ++column4x4) {
+      EXPECT_EQ(segmentation_map.segment_id(kBlockHeight4x4 + row4x4,
+                                            kBlockWidth4x4 + column4x4),
+                4);
+      EXPECT_EQ(segmentation_map2.segment_id(kBlockHeight4x4 + row4x4,
+                                             kBlockWidth4x4 + column4x4),
+                4);
+    }
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/segmentation_test.cc b/src/utils/segmentation_test.cc
new file mode 100644
index 0000000..e985b2d
--- /dev/null
+++ b/src/utils/segmentation_test.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/segmentation.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "src/utils/common.h"
+#include "src/utils/types.h"
+
+namespace libgav1 {
+namespace {
+
+int GetUnsignedBits(const unsigned int num_values) {
+  return (num_values > 0) ? FloorLog2(num_values) + 1 : 0;
+}
+
+// Check that kSegmentationFeatureBits and kSegmentationFeatureMaxValues are
+// consistent with each other.
+TEST(SegmentationTest, FeatureBitsAndMaxValuesConsistency) {
+  for (int feature = 0; feature < kSegmentFeatureMax; feature++) {
+    EXPECT_EQ(kSegmentationFeatureBits[feature],
+              GetUnsignedBits(kSegmentationFeatureMaxValues[feature]));
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/stack_test.cc b/src/utils/stack_test.cc
new file mode 100644
index 0000000..4de2ab6
--- /dev/null
+++ b/src/utils/stack_test.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/stack.h"
+
+#include <cstdint>
+#include <utility>
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr int kStackSize = 8;
+
+TEST(StackTest, SimpleType) {
+  Stack<int, kStackSize> stack;
+  EXPECT_TRUE(stack.Empty());
+
+  for (int i = 0; i < kStackSize; ++i) {
+    stack.Push(i);
+    EXPECT_FALSE(stack.Empty());
+  }
+
+  for (int i = kStackSize - 1; i >= 0; --i) {
+    EXPECT_EQ(stack.Pop(), i);
+  }
+  EXPECT_TRUE(stack.Empty());
+}
+
+TEST(StackTest, LargeStruct) {
+  struct LargeMoveOnlyStruct {
+    LargeMoveOnlyStruct() = default;
+    // Move only.
+    LargeMoveOnlyStruct(LargeMoveOnlyStruct&& other) = default;
+    LargeMoveOnlyStruct& operator=(LargeMoveOnlyStruct&& other) = default;
+
+    int32_t array1[1000];
+    uint64_t array2[2000];
+  };
+
+  Stack<LargeMoveOnlyStruct, kStackSize> stack;
+  EXPECT_TRUE(stack.Empty());
+
+  LargeMoveOnlyStruct large_move_only_struct[kStackSize];
+  for (int i = 0; i < kStackSize; ++i) {
+    LargeMoveOnlyStruct& l = large_move_only_struct[i];
+    l.array1[0] = i;
+    l.array2[0] = i;
+    stack.Push(std::move(l));
+    EXPECT_FALSE(stack.Empty());
+  }
+
+  for (int i = kStackSize - 1; i >= 0; --i) {
+    LargeMoveOnlyStruct l = stack.Pop();
+    EXPECT_EQ(l.array1[0], i);
+    EXPECT_EQ(l.array2[0], i);
+  }
+  EXPECT_TRUE(stack.Empty());
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/threadpool_test.cc b/src/utils/threadpool_test.cc
new file mode 100644
index 0000000..17854dc
--- /dev/null
+++ b/src/utils/threadpool_test.cc
@@ -0,0 +1,133 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/threadpool.h"
+
+#include <cassert>
+#include <cstdint>
+#include <memory>
+
+#include "absl/synchronization/mutex.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/executor.h"
+
+namespace libgav1 {
+namespace {
+
+class SimpleGuardedInteger {
+ public:
+  explicit SimpleGuardedInteger(int initial_value) : value_(initial_value) {}
+  SimpleGuardedInteger(const SimpleGuardedInteger&) = delete;
+  SimpleGuardedInteger& operator=(const SimpleGuardedInteger&) = delete;
+
+  void Decrement() {
+    absl::MutexLock l(&mutex_);
+    assert(value_ >= 1);
+    --value_;
+    changed_.SignalAll();
+  }
+
+  void Increment() {
+    absl::MutexLock l(&mutex_);
+    ++value_;
+    changed_.SignalAll();
+  }
+
+  int Value() {
+    absl::MutexLock l(&mutex_);
+    return value_;
+  }
+
+  void WaitForZero() {
+    absl::MutexLock l(&mutex_);
+    while (value_ != 0) {
+      changed_.Wait(&mutex_);
+    }
+  }
+
+ private:
+  absl::Mutex mutex_;
+  absl::CondVar changed_;
+  int value_ LIBGAV1_GUARDED_BY(mutex_);
+};
+
+// Loops for |milliseconds| of wall-clock time.
+void LoopForMs(int64_t milliseconds) {
+  const absl::Time deadline = absl::Now() + absl::Milliseconds(milliseconds);
+  while (absl::Now() < deadline) {
+  }
+}
+
+// A function that increments the given integer.
+void IncrementIntegerJob(SimpleGuardedInteger* value) {
+  LoopForMs(100);
+  value->Increment();
+}
+
+TEST(ThreadPoolTest, ThreadedIntegerIncrement) {
+  std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
+  ASSERT_NE(thread_pool, nullptr);
+  EXPECT_EQ(thread_pool->num_threads(), 100);
+  SimpleGuardedInteger count(0);
+  for (int i = 0; i < 1000; ++i) {
+    thread_pool->Schedule([&count]() { IncrementIntegerJob(&count); });
+  }
+  thread_pool.reset(nullptr);
+  EXPECT_EQ(count.Value(), 1000);
+}
+
+// Test a ThreadPool via the Executor interface.
+TEST(ThreadPoolTest, ExecutorInterface) {
+  std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
+  ASSERT_NE(thread_pool, nullptr);
+  std::unique_ptr<Executor> executor(thread_pool.release());
+  SimpleGuardedInteger count(0);
+  for (int i = 0; i < 1000; ++i) {
+    executor->Schedule([&count]() { IncrementIntegerJob(&count); });
+  }
+  executor.reset(nullptr);
+  EXPECT_EQ(count.Value(), 1000);
+}
+
+TEST(ThreadPoolTest, DestroyWithoutUse) {
+  std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
+  EXPECT_NE(thread_pool, nullptr);
+  thread_pool.reset(nullptr);
+}
+
+// If num_threads is 0, ThreadPool::Create() should return a null pointer.
+TEST(ThreadPoolTest, NumThreadsZero) {
+  std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(0);
+  EXPECT_EQ(thread_pool, nullptr);
+}
+
+// If num_threads is 1, the closures are run in FIFO order.
+TEST(ThreadPoolTest, OneThreadRunsClosuresFIFO) {
+  int count = 0;  // Declare first so that it outlives the thread pool.
+  std::unique_ptr<ThreadPool> pool = ThreadPool::Create(1);
+  ASSERT_NE(pool, nullptr);
+  EXPECT_EQ(pool->num_threads(), 1);
+  for (int i = 0; i < 1000; ++i) {
+    pool->Schedule([&count, i]() {
+      EXPECT_EQ(count, i);
+      count++;
+    });
+  }
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/unbounded_queue_test.cc b/src/utils/unbounded_queue_test.cc
new file mode 100644
index 0000000..b107ad0
--- /dev/null
+++ b/src/utils/unbounded_queue_test.cc
@@ -0,0 +1,163 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/unbounded_queue.h"
+
+#include <new>
+#include <utility>
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+class Integer {
+ public:
+  explicit Integer(int value) : value_(new (std::nothrow) int{value}) {}
+
+  // Move only.
+  Integer(Integer&& other) : value_(other.value_) { other.value_ = nullptr; }
+  Integer& operator=(Integer&& other) {
+    if (this != &other) {
+      delete value_;
+      value_ = other.value_;
+      other.value_ = nullptr;
+    }
+    return *this;
+  }
+
+  ~Integer() { delete value_; }
+
+  int value() const { return *value_; }
+
+ private:
+  int* value_;
+};
+
+TEST(UnboundedQueueTest, Basic) {
+  UnboundedQueue<int> queue;
+  ASSERT_TRUE(queue.Init());
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_TRUE(queue.GrowIfNeeded());
+    queue.Push(i);
+    EXPECT_FALSE(queue.Empty());
+  }
+
+  for (int i = 0; i < 8; ++i) {
+    EXPECT_FALSE(queue.Empty());
+    EXPECT_EQ(queue.Front(), i);
+    queue.Pop();
+  }
+  EXPECT_TRUE(queue.Empty());
+}
+
+TEST(UnboundedQueueTest, WrapAround) {
+  UnboundedQueue<int> queue;
+  ASSERT_TRUE(queue.Init());
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 1000; ++i) {
+    EXPECT_TRUE(queue.GrowIfNeeded());
+    queue.Push(i);
+    EXPECT_FALSE(queue.Empty());
+    EXPECT_EQ(queue.Front(), i);
+    queue.Pop();
+    EXPECT_TRUE(queue.Empty());
+  }
+}
+
+TEST(UnboundedQueueTest, EmptyBeforeInit) {
+  UnboundedQueue<int> queue;
+  EXPECT_TRUE(queue.Empty());
+}
+
+TEST(UnboundedQueueTest, LotsOfElements) {
+  UnboundedQueue<Integer> queue;
+  ASSERT_TRUE(queue.Init());
+  EXPECT_TRUE(queue.Empty());
+
+  for (int i = 0; i < 10000; ++i) {
+    Integer integer(i);
+    EXPECT_EQ(integer.value(), i);
+    EXPECT_TRUE(queue.GrowIfNeeded());
+    queue.Push(std::move(integer));
+    EXPECT_FALSE(queue.Empty());
+  }
+
+  for (int i = 0; i < 5000; ++i) {
+    EXPECT_FALSE(queue.Empty());
+    const Integer& integer = queue.Front();
+    EXPECT_EQ(integer.value(), i);
+    queue.Pop();
+  }
+  // Leave some elements in the queue to test destroying a nonempty queue.
+  EXPECT_FALSE(queue.Empty());
+}
+
+// Copy constructor and assignment are deleted, but move constructor and
+// assignment are OK.
+TEST(UnboundedQueueTest, Move) {
+  UnboundedQueue<int> ints1;
+  ASSERT_TRUE(ints1.Init());
+  EXPECT_TRUE(ints1.GrowIfNeeded());
+  ints1.Push(2);
+  EXPECT_TRUE(ints1.GrowIfNeeded());
+  ints1.Push(3);
+  EXPECT_TRUE(ints1.GrowIfNeeded());
+  ints1.Push(5);
+  EXPECT_TRUE(ints1.GrowIfNeeded());
+  ints1.Push(7);
+
+  // Move constructor.
+  UnboundedQueue<int> ints2(std::move(ints1));
+  EXPECT_EQ(ints2.Front(), 2);
+  ints2.Pop();
+  EXPECT_EQ(ints2.Front(), 3);
+  ints2.Pop();
+  EXPECT_EQ(ints2.Front(), 5);
+  ints2.Pop();
+  EXPECT_EQ(ints2.Front(), 7);
+  ints2.Pop();
+  EXPECT_TRUE(ints2.Empty());
+
+  EXPECT_TRUE(ints2.GrowIfNeeded());
+  ints2.Push(11);
+  EXPECT_TRUE(ints2.GrowIfNeeded());
+  ints2.Push(13);
+  EXPECT_TRUE(ints2.GrowIfNeeded());
+  ints2.Push(17);
+  EXPECT_TRUE(ints2.GrowIfNeeded());
+  ints2.Push(19);
+
+  // Move assignment.
+  UnboundedQueue<int> ints3;
+  ASSERT_TRUE(ints3.Init());
+  EXPECT_TRUE(ints3.GrowIfNeeded());
+  ints3.Push(23);
+  ints3 = std::move(ints2);
+  EXPECT_EQ(ints3.Front(), 11);
+  ints3.Pop();
+  EXPECT_EQ(ints3.Front(), 13);
+  ints3.Pop();
+  EXPECT_EQ(ints3.Front(), 17);
+  ints3.Pop();
+  EXPECT_EQ(ints3.Front(), 19);
+  ints3.Pop();
+  EXPECT_TRUE(ints3.Empty());
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/utils/vector_test.cc b/src/utils/vector_test.cc
new file mode 100644
index 0000000..5b0127c
--- /dev/null
+++ b/src/utils/vector_test.cc
@@ -0,0 +1,234 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/utils/vector.h"
+
+#include <memory>
+#include <new>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/utils/compiler_attributes.h"
+
+#if LIBGAV1_MSAN
+#include <sanitizer/msan_interface.h>
+#endif
+
+namespace libgav1 {
+namespace {
+
+class Foo {
+ public:
+  Foo() = default;
+
+  int x() const { return x_; }
+
+ private:
+  int x_ = 38;
+};
+
+class Point {
+ public:
+  Point(int x, int y) : x_(x), y_(y) {}
+
+  int x() const { return x_; }
+  int y() const { return y_; }
+
+ private:
+  int x_;
+  int y_;
+};
+
+TEST(VectorTest, NoCtor) {
+  VectorNoCtor<int> v;
+  EXPECT_TRUE(v.resize(100));
+  Vector<int> w;
+  EXPECT_TRUE(w.resize(100));
+
+#if LIBGAV1_MSAN
+  // Use MemorySanitizer to check VectorNoCtor::resize() does not initialize
+  // the memory while Vector::resize() does.
+  //
+  // __msan_test_shadow(const void *x, uptr size) returns the offset of the
+  // first (at least partially) poisoned byte in the range, or -1 if the whole
+  // range is good.
+  for (size_t i = 0; i < 100; ++i) {
+    EXPECT_EQ(__msan_test_shadow(&v[i], sizeof(int)), 0);
+    EXPECT_EQ(__msan_test_shadow(&w[i], sizeof(int)), -1);
+  }
+#endif
+}
+
+TEST(VectorTest, Constructor) {
+  Vector<Foo> v;
+  EXPECT_TRUE(v.resize(100));
+  for (const Foo& foo : v) {
+    EXPECT_EQ(foo.x(), 38);
+  }
+}
+
+TEST(VectorTest, PushBack) {
+  // Create a vector containing integers
+  Vector<int> v;
+  EXPECT_TRUE(v.reserve(8));
+  EXPECT_EQ(v.size(), 0);
+
+  EXPECT_TRUE(v.push_back(25));
+  EXPECT_EQ(v.size(), 1);
+  EXPECT_EQ(v[0], 25);
+
+  EXPECT_TRUE(v.push_back(13));
+  EXPECT_EQ(v.size(), 2);
+  EXPECT_EQ(v[0], 25);
+  EXPECT_EQ(v[1], 13);
+}
+
+TEST(VectorTest, PushBackUnchecked) {
+  Vector<std::unique_ptr<Point>> v;
+  EXPECT_TRUE(v.reserve(2));
+  EXPECT_EQ(v.size(), 0);
+
+  std::unique_ptr<Point> point(new (std::nothrow) Point(1, 2));
+  EXPECT_NE(point, nullptr);
+  v.push_back_unchecked(std::move(point));
+  EXPECT_EQ(v.size(), 1);
+  EXPECT_EQ(v[0]->x(), 1);
+  EXPECT_EQ(v[0]->y(), 2);
+
+  point.reset(new (std::nothrow) Point(3, 4));
+  EXPECT_NE(point, nullptr);
+  v.push_back_unchecked(std::move(point));
+  EXPECT_EQ(v.size(), 2);
+  EXPECT_EQ(v[0]->x(), 1);
+  EXPECT_EQ(v[0]->y(), 2);
+  EXPECT_EQ(v[1]->x(), 3);
+  EXPECT_EQ(v[1]->y(), 4);
+}
+
+TEST(VectorTest, EmplaceBack) {
+  Vector<Point> v;
+  EXPECT_EQ(v.size(), 0);
+
+  EXPECT_TRUE(v.emplace_back(1, 2));
+  EXPECT_EQ(v.size(), 1);
+  EXPECT_EQ(v[0].x(), 1);
+  EXPECT_EQ(v[0].y(), 2);
+
+  EXPECT_TRUE(v.emplace_back(3, 4));
+  EXPECT_EQ(v.size(), 2);
+  EXPECT_EQ(v[0].x(), 1);
+  EXPECT_EQ(v[0].y(), 2);
+  EXPECT_EQ(v[1].x(), 3);
+  EXPECT_EQ(v[1].y(), 4);
+}
+
+// Copy constructor and assignment are deleted, but move constructor and
+// assignment are OK.
+TEST(VectorTest, Move) {
+  Vector<int> ints1;
+  EXPECT_TRUE(ints1.reserve(4));
+  EXPECT_TRUE(ints1.push_back(2));
+  EXPECT_TRUE(ints1.push_back(3));
+  EXPECT_TRUE(ints1.push_back(5));
+  EXPECT_TRUE(ints1.push_back(7));
+
+  // Move constructor.
+  Vector<int> ints2(std::move(ints1));
+  EXPECT_EQ(ints2.size(), 4);
+  EXPECT_EQ(ints2[0], 2);
+  EXPECT_EQ(ints2[1], 3);
+  EXPECT_EQ(ints2[2], 5);
+  EXPECT_EQ(ints2[3], 7);
+
+  // Move assignment.
+  Vector<int> ints3;
+  EXPECT_TRUE(ints3.reserve(1));
+  EXPECT_TRUE(ints3.push_back(11));
+  ints3 = std::move(ints2);
+  EXPECT_EQ(ints3.size(), 4);
+  EXPECT_EQ(ints3[0], 2);
+  EXPECT_EQ(ints3[1], 3);
+  EXPECT_EQ(ints3[2], 5);
+  EXPECT_EQ(ints3[3], 7);
+}
+
+TEST(VectorTest, Erase) {
+  Vector<int> ints;
+  EXPECT_TRUE(ints.reserve(4));
+  EXPECT_TRUE(ints.push_back(2));
+  EXPECT_TRUE(ints.push_back(3));
+  EXPECT_TRUE(ints.push_back(5));
+  EXPECT_TRUE(ints.push_back(7));
+
+  EXPECT_EQ(ints.size(), 4);
+  EXPECT_EQ(ints[0], 2);
+  EXPECT_EQ(ints[1], 3);
+  EXPECT_EQ(ints[2], 5);
+  EXPECT_EQ(ints[3], 7);
+
+  ints.erase(ints.begin());
+  EXPECT_EQ(ints.size(), 3);
+  EXPECT_EQ(ints[0], 3);
+  EXPECT_EQ(ints[1], 5);
+  EXPECT_EQ(ints[2], 7);
+}
+
+TEST(VectorTest, EraseNonTrivial) {
+  // A simple class that sets an int value to 0 in the destructor.
+  class Cleaner {
+   public:
+    explicit Cleaner(int* value) : value_(value) {}
+    ~Cleaner() { *value_ = 0; }
+
+    int value() const { return *value_; }
+
+   private:
+    int* value_;
+  };
+  int value1 = 100;
+  int value2 = 200;
+  Vector<std::unique_ptr<Cleaner>> v;
+  EXPECT_TRUE(v.reserve(2));
+  EXPECT_EQ(v.capacity(), 2);
+
+  std::unique_ptr<Cleaner> c(new (std::nothrow) Cleaner(&value1));
+  EXPECT_NE(c, nullptr);
+  EXPECT_TRUE(v.push_back(std::move(c)));
+  c.reset(new (std::nothrow) Cleaner(&value2));
+  EXPECT_NE(c, nullptr);
+  EXPECT_TRUE(v.push_back(std::move(c)));
+  EXPECT_EQ(v.size(), 2);
+  EXPECT_EQ(value1, 100);
+  EXPECT_EQ(value2, 200);
+
+  v.erase(v.begin());
+  EXPECT_EQ(v.size(), 1);
+  EXPECT_EQ(v.capacity(), 2);
+  EXPECT_EQ(value1, 0);
+  EXPECT_EQ(value2, 200);
+  EXPECT_EQ(v[0].get()->value(), value2);
+
+  EXPECT_TRUE(v.shrink_to_fit());
+  EXPECT_EQ(v.size(), 1);
+  EXPECT_EQ(v.capacity(), 1);
+  EXPECT_EQ(value2, 200);
+  EXPECT_EQ(v[0].get()->value(), value2);
+
+  v.clear();
+  EXPECT_TRUE(v.empty());
+  EXPECT_EQ(value2, 0);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/version_test.cc b/src/version_test.cc
new file mode 100644
index 0000000..aaa5e1c
--- /dev/null
+++ b/src/version_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/gav1/version.h"
+
+#include <regex>  // NOLINT (unapproved c++11 header)
+
+#include "gtest/gtest.h"
+
+namespace libgav1 {
+namespace {
+
+TEST(VersionTest, GetVersion) {
+  const int library_version = GetVersion();
+  EXPECT_EQ((library_version >> 24) & 0xff, 0);
+  // Note if we link against a shared object there's potential for a mismatch
+  // if a different library is loaded at runtime.
+  EXPECT_EQ((library_version >> 16) & 0xff, LIBGAV1_MAJOR_VERSION);
+  EXPECT_EQ((library_version >> 8) & 0xff, LIBGAV1_MINOR_VERSION);
+  EXPECT_EQ(library_version & 0xff, LIBGAV1_PATCH_VERSION);
+
+  const int header_version = LIBGAV1_VERSION;
+  EXPECT_EQ((header_version >> 24) & 0xff, 0);
+  EXPECT_EQ((header_version >> 16) & 0xff, LIBGAV1_MAJOR_VERSION);
+  EXPECT_EQ((header_version >> 8) & 0xff, LIBGAV1_MINOR_VERSION);
+  EXPECT_EQ(header_version & 0xff, LIBGAV1_PATCH_VERSION);
+}
+
+TEST(VersionTest, GetVersionString) {
+  const char* version = GetVersionString();
+  ASSERT_NE(version, nullptr);
+  // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
+  const std::regex semver_regex(
+      R"(^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*))"
+      R"((?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))"
+      R"((?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?)"
+      R"((?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$)");
+
+  EXPECT_TRUE(std::regex_match(version, semver_regex)) << version;
+  // Regex validation:
+  // It shouldn't accept a version starting with a non-digit.
+  version = "v1.2.3";
+  EXPECT_FALSE(std::regex_match(version, semver_regex)) << version;
+  // It shouldn't accept a version with spaces."
+  version = "1.2.3 alpha";
+  EXPECT_FALSE(std::regex_match(version, semver_regex)) << version;
+}
+
+TEST(VersionTest, GetBuildConfiguration) {
+  const char* config = GetBuildConfiguration();
+  ASSERT_NE(config, nullptr);
+}
+
+}  // namespace
+}  // namespace libgav1
diff --git a/src/warp_prediction_test.cc b/src/warp_prediction_test.cc
new file mode 100644
index 0000000..46f262f
--- /dev/null
+++ b/src/warp_prediction_test.cc
@@ -0,0 +1,246 @@
+// Copyright 2021 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/warp_prediction.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <ostream>
+
+#include "absl/base/macros.h"
+#include "gtest/gtest.h"
+#include "src/obu_parser.h"
+#include "src/utils/common.h"
+#include "src/utils/constants.h"
+#include "src/utils/types.h"
+#include "tests/third_party/libvpx/acm_random.h"
+
+namespace libgav1 {
+namespace {
+
+constexpr int16_t kExpectedWarpParamsOutput[10][4] = {
+    {0, 0, 0, 0},
+    {2880, 2880, 2752, 2752},
+    {-1408, -1408, -1472, -1472},
+    {0, 0, 0, 0},
+    {6784, 6784, 6144, 6144},  // Invalid.
+    {-5312, -5312, -5824, -5824},
+    {-3904, -3904, -4160, -4160},
+    {2496, 2496, 2368, 2368},
+    {1024, 1024, 1024, 1024},
+    {-7808, -7808, -8832, -8832},  // Invalid.
+};
+
+constexpr bool kExpectedWarpValid[10] = {
+    true, true, true, true, false, true, true, true, true, false,
+};
+
+int RandomWarpedParam(int seed_offset, int bits) {
+  libvpx_test::ACMRandom rnd(seed_offset +
+                             libvpx_test::ACMRandom::DeterministicSeed());
+  // 1 in 8 chance of generating zero (arbitrary).
+  const bool zero = (rnd.Rand16() & 7) == 0;
+  if (zero) return 0;
+  // Generate uniform values in the range [-(1 << bits), 1] U [1, 1 << bits].
+  const int mask = (1 << bits) - 1;
+  const int value = 1 + (rnd.RandRange(1U << 31) & mask);
+  const bool sign = (rnd.Rand16() & 1) != 0;
+  return sign ? value : -value;
+}
+
+void GenerateWarpedModel(GlobalMotion* warp_params, int seed) {
+  do {
+    warp_params->params[0] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+    warp_params->params[1] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits + 6);
+    warp_params->params[2] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+        (1 << kWarpedModelPrecisionBits);
+    warp_params->params[3] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+    warp_params->params[4] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3);
+    warp_params->params[5] =
+        RandomWarpedParam(seed, kWarpedModelPrecisionBits - 3) +
+        (1 << kWarpedModelPrecisionBits);
+  } while (warp_params->params[2] == 0);
+}
+
+TEST(WarpPredictionTest, SetupShear) {
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(kExpectedWarpParamsOutput); ++i) {
+    GlobalMotion warp_params;
+    GenerateWarpedModel(&warp_params, static_cast<int>(i));
+    const bool warp_valid = SetupShear(&warp_params);
+
+    SCOPED_TRACE(testing::Message() << "Test failure at iteration: " << i);
+    EXPECT_EQ(warp_valid, kExpectedWarpValid[i]);
+    EXPECT_EQ(warp_params.alpha, kExpectedWarpParamsOutput[i][0]);
+    EXPECT_EQ(warp_params.beta, kExpectedWarpParamsOutput[i][1]);
+    EXPECT_EQ(warp_params.gamma, kExpectedWarpParamsOutput[i][2]);
+    EXPECT_EQ(warp_params.delta, kExpectedWarpParamsOutput[i][3]);
+  }
+
+  // Test signed shift behavior in delta and gamma generation.
+  GlobalMotion warp_params;
+  warp_params.params[0] = 24748;
+  warp_params.params[1] = -142530;
+  warp_params.params[2] = 65516;
+  warp_params.params[3] = -640;
+  warp_params.params[4] = 256;
+  warp_params.params[5] = 65310;
+  EXPECT_TRUE(SetupShear(&warp_params));
+  EXPECT_EQ(warp_params.alpha, 0);
+  EXPECT_EQ(warp_params.beta, -640);
+  EXPECT_EQ(warp_params.gamma, 256);
+  EXPECT_EQ(warp_params.delta, -192);
+
+  warp_params.params[0] = 24748;
+  warp_params.params[1] = -142530;
+  warp_params.params[2] = 61760;
+  warp_params.params[3] = -640;
+  warp_params.params[4] = -13312;
+  warp_params.params[5] = 65310;
+  EXPECT_TRUE(SetupShear(&warp_params));
+  EXPECT_EQ(warp_params.alpha, -3776);
+  EXPECT_EQ(warp_params.beta, -640);
+  EXPECT_EQ(warp_params.gamma, -14144);
+  EXPECT_EQ(warp_params.delta, -384);
+}
+
+struct WarpInputParam {
+  WarpInputParam(int num_samples, int block_width4x4, int block_height4x4)
+      : num_samples(num_samples),
+        block_width4x4(block_width4x4),
+        block_height4x4(block_height4x4) {}
+  int num_samples;
+  int block_width4x4;
+  int block_height4x4;
+};
+
+std::ostream& operator<<(std::ostream& os, const WarpInputParam& param) {
+  return os << "num_samples: " << param.num_samples
+            << ", block_(width/height)4x4: " << param.block_width4x4 << "x"
+            << param.block_height4x4;
+}
+
+const WarpInputParam warp_test_param[] = {
+    // sample = 1.
+    WarpInputParam(1, 1, 1),
+    WarpInputParam(1, 1, 2),
+    WarpInputParam(1, 2, 1),
+    WarpInputParam(1, 2, 2),
+    WarpInputParam(1, 2, 4),
+    WarpInputParam(1, 4, 2),
+    WarpInputParam(1, 4, 4),
+    WarpInputParam(1, 4, 8),
+    WarpInputParam(1, 8, 4),
+    WarpInputParam(1, 8, 8),
+    WarpInputParam(1, 8, 16),
+    WarpInputParam(1, 16, 8),
+    WarpInputParam(1, 16, 16),
+    WarpInputParam(1, 16, 32),
+    WarpInputParam(1, 32, 16),
+    WarpInputParam(1, 32, 32),
+    // sample = 8.
+    WarpInputParam(8, 1, 1),
+    WarpInputParam(8, 1, 2),
+    WarpInputParam(8, 2, 1),
+    WarpInputParam(8, 2, 2),
+    WarpInputParam(8, 2, 4),
+    WarpInputParam(8, 4, 2),
+    WarpInputParam(8, 4, 4),
+    WarpInputParam(8, 4, 8),
+    WarpInputParam(8, 8, 4),
+    WarpInputParam(8, 8, 8),
+    WarpInputParam(8, 8, 16),
+    WarpInputParam(8, 16, 8),
+    WarpInputParam(8, 16, 16),
+    WarpInputParam(8, 16, 32),
+    WarpInputParam(8, 32, 16),
+    WarpInputParam(8, 32, 32),
+};
+
+constexpr bool kExpectedWarpEstimationValid[2] = {false, true};
+
+constexpr int kExpectedWarpEstimationOutput[16][6] = {
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {8388607, 8388607, 57345, -8191, -8191, 57345},
+    {2146296, 1589240, 57345, 8191, -8191, 73727},
+    {1753128, 1196072, 73727, -8191, 8191, 57345},
+    {-8388608, -8388608, 73727, 8191, 8191, 73727},
+    {-4435485, -8388608, 65260, 8191, 8191, 73727},
+    {-8388608, -7552929, 73727, 8191, 8191, 68240},
+    {-8388608, -8388608, 73727, 8191, 8191, 70800},
+};
+
+class WarpEstimationTest : public testing::TestWithParam<WarpInputParam> {
+ public:
+  WarpEstimationTest() = default;
+  ~WarpEstimationTest() override = default;
+
+ protected:
+  WarpInputParam param_ = GetParam();
+};
+
+TEST_P(WarpEstimationTest, WarpEstimation) {
+  // Set input params.
+  libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
+  const int row4x4 = rnd.Rand8();
+  const int column4x4 = rnd.Rand8();
+  MotionVector mv;
+  mv.mv[0] = rnd.Rand8();
+  mv.mv[1] = rnd.Rand8();
+  int candidates[kMaxLeastSquaresSamples][4];
+  for (int i = 0; i < param_.num_samples; ++i) {
+    // Make candidates relative to the top left of frame.
+    candidates[i][0] = rnd.Rand8() + MultiplyBy32(row4x4);
+    candidates[i][1] = rnd.Rand8() + MultiplyBy32(column4x4);
+    candidates[i][2] = rnd.Rand8() + MultiplyBy32(row4x4);
+    candidates[i][3] = rnd.Rand8() + MultiplyBy32(column4x4);
+  }
+
+  // Get output.
+  GlobalMotion warp_params;
+  const bool warp_success = WarpEstimation(
+      param_.num_samples, param_.block_width4x4, param_.block_height4x4, row4x4,
+      column4x4, mv, candidates, &warp_params);
+  if (param_.num_samples == 1) {
+    EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[0]);
+  } else {
+    EXPECT_EQ(warp_success, kExpectedWarpEstimationValid[1]);
+    int index = FloorLog2(param_.block_width4x4) * 3 - 1;
+    if (param_.block_width4x4 == param_.block_height4x4) {
+      index += 1;
+    } else if (param_.block_width4x4 < param_.block_height4x4) {
+      index += 2;
+    }
+    for (size_t i = 0; i < ABSL_ARRAYSIZE(warp_params.params); ++i) {
+      EXPECT_EQ(warp_params.params[i], kExpectedWarpEstimationOutput[index][i]);
+    }
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(WarpFuncTest, WarpEstimationTest,
+                         testing::ValuesIn(warp_test_param));
+}  // namespace
+}  // namespace libgav1
diff --git a/tests/block_utils.cc b/tests/block_utils.cc
new file mode 100644
index 0000000..a68ae64
--- /dev/null
+++ b/tests/block_utils.cc
@@ -0,0 +1,134 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/block_utils.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+namespace libgav1 {
+namespace test_utils {
+namespace {
+
+#define LIBGAV1_DEBUG_FORMAT_CODE "x"
+template <typename Pixel>
+void PrintBlockDiff(const Pixel* block1, const Pixel* block2, int width,
+                    int height, int stride1, int stride2,
+                    const bool print_padding) {
+  const int print_width = print_padding ? std::min(stride1, stride2) : width;
+  const int field_width = (sizeof(Pixel) == 1) ? 4 : 5;
+
+  for (int y = 0; y < height; ++y) {
+    printf("[%2d] ", y);
+    for (int x = 0; x < print_width; ++x) {
+      if (x >= width) {
+        if (block1[x] == block2[x]) {
+          printf("[%*" LIBGAV1_DEBUG_FORMAT_CODE "] ", field_width, block1[x]);
+        } else {
+          printf("[*%*" LIBGAV1_DEBUG_FORMAT_CODE "] ", field_width - 1,
+                 block1[x]);
+        }
+      } else {
+        if (block1[x] == block2[x]) {
+          printf("%*" LIBGAV1_DEBUG_FORMAT_CODE " ", field_width, block1[x]);
+        } else {
+          printf("*%*" LIBGAV1_DEBUG_FORMAT_CODE " ", field_width - 1,
+                 block1[x]);
+        }
+      }
+    }
+    printf("\n");
+    block1 += stride1;
+    block2 += stride2;
+  }
+}
+
+}  // namespace
+
+template <typename Pixel>
+void PrintBlock(const Pixel* block, int width, int height, int stride,
+                const bool print_padding /*= false*/) {
+  const int print_width = print_padding ? stride : width;
+  const int field_width = (sizeof(Pixel) == 1) ? 4 : 5;
+  for (int y = 0; y < height; ++y) {
+    printf("[%2d] ", y);
+    for (int x = 0; x < print_width; ++x) {
+      if (x >= width) {
+        printf("[%*" LIBGAV1_DEBUG_FORMAT_CODE "] ", field_width, block[x]);
+      } else {
+        printf("%*" LIBGAV1_DEBUG_FORMAT_CODE " ", field_width, block[x]);
+      }
+    }
+    printf("\n");
+    block += stride;
+  }
+}
+#undef LIBGAV1_DEBUG_FORMAT_CODE
+
+template void PrintBlock(const uint8_t* block, int width, int height,
+                         int stride, bool print_padding /*= false*/);
+template void PrintBlock(const uint16_t* block, int width, int height,
+                         int stride, bool print_padding /*= false*/);
+template void PrintBlock(const int8_t* block, int width, int height, int stride,
+                         bool print_padding /*= false*/);
+template void PrintBlock(const int16_t* block, int width, int height,
+                         int stride, bool print_padding /*= false*/);
+
+template <typename Pixel>
+bool CompareBlocks(const Pixel* block1, const Pixel* block2, int width,
+                   int height, int stride1, int stride2,
+                   const bool check_padding, const bool print_diff /*= true*/) {
+  bool ok = true;
+  const int check_width = check_padding ? std::min(stride1, stride2) : width;
+  for (int y = 0; y < height; ++y) {
+    const uint64_t row1 = static_cast<uint64_t>(y) * stride1;
+    const uint64_t row2 = static_cast<uint64_t>(y) * stride2;
+    ok = memcmp(block1 + row1, block2 + row2,
+                sizeof(block1[0]) * check_width) == 0;
+    if (!ok) break;
+  }
+  if (!ok && print_diff) {
+    printf("block1 (width: %d height: %d stride: %d):\n", width, height,
+           stride1);
+    PrintBlockDiff(block1, block2, width, height, stride1, stride2,
+                   check_padding);
+    printf("\nblock2 (width: %d height: %d stride: %d):\n", width, height,
+           stride2);
+    PrintBlockDiff(block2, block1, width, height, stride2, stride1,
+                   check_padding);
+  }
+  return ok;
+}
+
+template bool CompareBlocks(const uint8_t* block1, const uint8_t* block2,
+                            int width, int height, int stride1, int stride2,
+                            const bool check_padding,
+                            const bool print_diff /*= true*/);
+template bool CompareBlocks(const uint16_t* block1, const uint16_t* block2,
+                            int width, int height, int stride1, int stride2,
+                            const bool check_padding,
+                            const bool print_diff /*= true*/);
+template bool CompareBlocks(const int8_t* block1, const int8_t* block2,
+                            int width, int height, int stride1, int stride2,
+                            const bool check_padding,
+                            const bool print_diff /*= true*/);
+template bool CompareBlocks(const int16_t* block1, const int16_t* block2,
+                            int width, int height, int stride1, int stride2,
+                            const bool check_padding,
+                            const bool print_diff /*= true*/);
+
+}  // namespace test_utils
+}  // namespace libgav1
diff --git a/tests/block_utils.h b/tests/block_utils.h
new file mode 100644
index 0000000..4542420
--- /dev/null
+++ b/tests/block_utils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBGAV1_TESTS_BLOCK_UTILS_H_
+#define LIBGAV1_TESTS_BLOCK_UTILS_H_
+
+#include <cstdint>
+
+namespace libgav1 {
+namespace test_utils {
+
+//------------------------------------------------------------------------------
+// Prints |block| pixel by pixel with |width| pixels per row if |print_padding|
+// is false, |stride| otherwise. If |print_padding| is true padding pixels are
+// surrounded in '[]'.
+template <typename Pixel>
+void PrintBlock(const Pixel* block, int width, int height, int stride,
+                bool print_padding = false);
+
+extern template void PrintBlock(const uint8_t* block, int width, int height,
+                                int stride, bool print_padding /*= false*/);
+extern template void PrintBlock(const uint16_t* block, int width, int height,
+                                int stride, bool print_padding /*= false*/);
+
+//------------------------------------------------------------------------------
+// Compares |block1| and |block2| pixel by pixel checking |width| pixels per row
+// if |check_padding| is false, min(|stride1|, |stride2|) pixels otherwise.
+// Prints the blocks with differences marked with a '*' if |print_diff| is
+// true (the default).
+
+template <typename Pixel>
+bool CompareBlocks(const Pixel* block1, const Pixel* block2, int width,
+                   int height, int stride1, int stride2, bool check_padding,
+                   bool print_diff = true);
+
+extern template bool CompareBlocks(const uint8_t* block1, const uint8_t* block2,
+                                   int width, int height, int stride1,
+                                   int stride2, bool check_padding,
+                                   bool print_diff /*= true*/);
+extern template bool CompareBlocks(const uint16_t* block1,
+                                   const uint16_t* block2, int width,
+                                   int height, int stride1, int stride2,
+                                   bool check_padding,
+                                   bool print_diff /*= true*/);
+
+}  // namespace test_utils
+}  // namespace libgav1
+
+#endif  // LIBGAV1_TESTS_BLOCK_UTILS_H_
diff --git a/tests/data/five-frames.ivf b/tests/data/five-frames.ivf
new file mode 100644
index 0000000..08bc6db
--- /dev/null
+++ b/tests/data/five-frames.ivf
Binary files differ
diff --git a/tests/data/ivf-header-and-truncated-frame-header b/tests/data/ivf-header-and-truncated-frame-header
new file mode 100644
index 0000000..c6d7a6a
--- /dev/null
+++ b/tests/data/ivf-header-and-truncated-frame-header
Binary files differ
diff --git a/tests/data/ivf-header-only b/tests/data/ivf-header-only
new file mode 100644
index 0000000..e751f36
--- /dev/null
+++ b/tests/data/ivf-header-only
Binary files differ
diff --git a/tests/data/ivf-signature-only b/tests/data/ivf-signature-only
new file mode 100644
index 0000000..8550ef8
--- /dev/null
+++ b/tests/data/ivf-signature-only
@@ -0,0 +1 @@
+DKIF
diff --git a/tests/data/one-frame-large-timestamp.ivf b/tests/data/one-frame-large-timestamp.ivf
new file mode 100644
index 0000000..44886da
--- /dev/null
+++ b/tests/data/one-frame-large-timestamp.ivf
Binary files differ
diff --git a/tests/data/one-frame-truncated.ivf b/tests/data/one-frame-truncated.ivf
new file mode 100644
index 0000000..94e5b09
--- /dev/null
+++ b/tests/data/one-frame-truncated.ivf
Binary files differ
diff --git a/tests/data/one-frame.ivf b/tests/data/one-frame.ivf
new file mode 100644
index 0000000..436e461
--- /dev/null
+++ b/tests/data/one-frame.ivf
Binary files differ
diff --git a/tests/libgav1_tests.cmake b/tests/libgav1_tests.cmake
new file mode 100644
index 0000000..c759d4f
--- /dev/null
+++ b/tests/libgav1_tests.cmake
@@ -0,0 +1,1367 @@
+# Copyright 2020 The libgav1 Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if(LIBGAV1_LIBGAV1_TESTS_CMAKE_)
+  return()
+endif() # LIBGAV1_LIBGAV1_TESTS_CMAKE_
+set(LIBGAV1_LIBGAV1_TESTS_CMAKE_ 1)
+
+set(libgav1_googletest "${libgav1_root}/third_party/googletest")
+if(NOT LIBGAV1_ENABLE_TESTS OR NOT EXISTS "${libgav1_googletest}")
+  macro(libgav1_add_tests_targets)
+
+  endmacro()
+
+  if(LIBGAV1_ENABLE_TESTS AND NOT EXISTS "${libgav1_googletest}")
+    message(
+      "GoogleTest not found, setting LIBGAV1_ENABLE_TESTS to false.\n"
+      "To enable tests download the GoogleTest repository to"
+      " third_party/googletest:\n\n  git \\\n    -C ${libgav1_root} \\\n"
+      "    clone \\\n"
+      "    https://github.com/google/googletest.git third_party/googletest\n")
+    set(LIBGAV1_ENABLE_TESTS FALSE CACHE BOOL "Enables tests." FORCE)
+  endif()
+  return()
+endif()
+
+# Check GoogleTest compiler requirements.
+if((CMAKE_CXX_COMPILER_ID
+    MATCHES
+    "Clang|GNU"
+    AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5")
+   OR (MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19"))
+  macro(libgav1_add_tests_targets)
+
+  endmacro()
+
+  message(
+    WARNING
+      "${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_ID} version"
+      " ${CMAKE_CXX_COMPILER_VERSION}) is below the minimum requirements for"
+      " GoogleTest; disabling unit tests. See"
+      " https://github.com/google/googletest#compilers for more detail.")
+  set(LIBGAV1_ENABLE_TESTS FALSE CACHE BOOL "Enables tests." FORCE)
+  return()
+endif()
+
+list(APPEND libgav1_tests_block_utils_sources
+            "${libgav1_root}/tests/block_utils.h"
+            "${libgav1_root}/tests/block_utils.cc")
+
+list(APPEND libgav1_tests_utils_sources
+            "${libgav1_root}/tests/third_party/libvpx/acm_random.h"
+            "${libgav1_root}/tests/third_party/libvpx/md5_helper.h"
+            "${libgav1_root}/tests/third_party/libvpx/md5_utils.cc"
+            "${libgav1_root}/tests/third_party/libvpx/md5_utils.h"
+            "${libgav1_root}/tests/utils.h" "${libgav1_root}/tests/utils.cc")
+
+list(APPEND libgav1_tests_utils_test_sources
+            "${libgav1_root}/tests/utils_test.cc")
+
+list(APPEND libgav1_array_2d_test_sources
+            "${libgav1_source}/utils/array_2d_test.cc")
+list(APPEND libgav1_average_blend_test_sources
+            "${libgav1_source}/dsp/average_blend_test.cc")
+list(APPEND libgav1_block_parameters_holder_test_sources
+            "${libgav1_source}/utils/block_parameters_holder_test.cc")
+list(APPEND libgav1_blocking_counter_test_sources
+            "${libgav1_source}/utils/blocking_counter_test.cc")
+list(APPEND libgav1_buffer_pool_test_sources
+            "${libgav1_source}/buffer_pool_test.cc")
+list(APPEND libgav1_cdef_test_sources "${libgav1_source}/dsp/cdef_test.cc")
+list(
+  APPEND libgav1_common_test_sources "${libgav1_source}/utils/common_test.cc")
+list(APPEND libgav1_common_avx2_test_sources
+            "${libgav1_source}/dsp/x86/common_avx2.h"
+            "${libgav1_source}/dsp/x86/common_avx2.inc"
+            "${libgav1_source}/dsp/x86/common_avx2_test.cc"
+            "${libgav1_source}/dsp/x86/common_sse4.inc")
+list(APPEND libgav1_common_neon_test_sources
+            "${libgav1_source}/dsp/arm/common_neon_test.cc")
+list(APPEND libgav1_common_sse4_test_sources
+            "${libgav1_source}/dsp/x86/common_sse4.h"
+            "${libgav1_source}/dsp/x86/common_sse4.inc"
+            "${libgav1_source}/dsp/x86/common_sse4_test.cc")
+list(APPEND libgav1_convolve_test_sources
+            "${libgav1_source}/dsp/convolve_test.cc")
+list(APPEND libgav1_cpu_test_sources "${libgav1_source}/utils/cpu_test.cc")
+list(APPEND libgav1_c_decoder_test_sources
+            "${libgav1_source}/c_decoder_test.c"
+            "${libgav1_source}/decoder_test_data.h")
+list(APPEND libgav1_c_version_test_sources "${libgav1_source}/c_version_test.c")
+list(APPEND libgav1_decoder_test_sources
+            "${libgav1_source}/decoder_test.cc"
+            "${libgav1_source}/decoder_test_data.h")
+list(APPEND libgav1_decoder_buffer_test_sources
+            "${libgav1_source}/decoder_buffer_test.cc")
+list(APPEND libgav1_distance_weighted_blend_test_sources
+            "${libgav1_source}/dsp/distance_weighted_blend_test.cc")
+list(APPEND libgav1_dsp_test_sources "${libgav1_source}/dsp/dsp_test.cc")
+list(APPEND libgav1_entropy_decoder_test_sources
+            "${libgav1_source}/utils/entropy_decoder_test.cc"
+            "${libgav1_source}/utils/entropy_decoder_test_data.inc")
+list(APPEND libgav1_file_reader_test_sources
+            "${libgav1_examples}/file_reader_test.cc"
+            "${libgav1_examples}/file_reader_test_common.cc"
+            "${libgav1_examples}/file_reader_test_common.h")
+list(APPEND libgav1_film_grain_test_sources
+            "${libgav1_source}/film_grain_test.cc")
+list(APPEND libgav1_file_reader_factory_test_sources
+            "${libgav1_examples}/file_reader_factory_test.cc")
+list(APPEND libgav1_file_writer_test_sources
+            "${libgav1_examples}/file_writer_test.cc")
+list(APPEND libgav1_internal_frame_buffer_list_test_sources
+            "${libgav1_source}/internal_frame_buffer_list_test.cc")
+list(APPEND libgav1_intra_edge_test_sources
+            "${libgav1_source}/dsp/intra_edge_test.cc")
+list(APPEND libgav1_intrapred_cfl_test_sources
+            "${libgav1_source}/dsp/intrapred_cfl_test.cc")
+list(APPEND libgav1_intrapred_directional_test_sources
+            "${libgav1_source}/dsp/intrapred_directional_test.cc")
+list(APPEND libgav1_intrapred_filter_test_sources
+            "${libgav1_source}/dsp/intrapred_filter_test.cc")
+list(APPEND libgav1_intrapred_test_sources
+            "${libgav1_source}/dsp/intrapred_test.cc")
+list(APPEND libgav1_inverse_transform_test_sources
+            "${libgav1_source}/dsp/inverse_transform_test.cc")
+list(APPEND libgav1_loop_filter_test_sources
+            "${libgav1_source}/dsp/loop_filter_test.cc")
+list(APPEND libgav1_loop_restoration_test_sources
+            "${libgav1_source}/dsp/loop_restoration_test.cc")
+list(APPEND libgav1_mask_blend_test_sources
+            "${libgav1_source}/dsp/mask_blend_test.cc")
+list(APPEND libgav1_motion_field_projection_test_sources
+            "${libgav1_source}/dsp/motion_field_projection_test.cc")
+list(APPEND libgav1_motion_vector_search_test_sources
+            "${libgav1_source}/dsp/motion_vector_search_test.cc")
+list(APPEND libgav1_super_res_test_sources
+            "${libgav1_source}/dsp/super_res_test.cc")
+list(APPEND libgav1_weight_mask_test_sources
+            "${libgav1_source}/dsp/weight_mask_test.cc")
+list(
+  APPEND libgav1_memory_test_sources "${libgav1_source}/utils/memory_test.cc")
+list(APPEND libgav1_obmc_test_sources "${libgav1_source}/dsp/obmc_test.cc")
+list(APPEND libgav1_obu_parser_test_sources
+            "${libgav1_source}/obu_parser_test.cc")
+list(APPEND libgav1_post_filter_test_sources
+            "${libgav1_source}/post_filter_test.cc")
+list(APPEND libgav1_prediction_mask_test_sources
+            "${libgav1_source}/prediction_mask_test.cc")
+list(
+  APPEND libgav1_quantizer_test_sources "${libgav1_source}/quantizer_test.cc")
+list(APPEND libgav1_queue_test_sources "${libgav1_source}/utils/queue_test.cc")
+list(APPEND libgav1_raw_bit_reader_test_sources
+            "${libgav1_source}/utils/raw_bit_reader_test.cc")
+list(APPEND libgav1_reconstruction_test_sources
+            "${libgav1_source}/reconstruction_test.cc")
+list(APPEND libgav1_residual_buffer_pool_test_sources
+            "${libgav1_source}/residual_buffer_pool_test.cc")
+list(APPEND libgav1_scan_test_sources "${libgav1_source}/scan_test.cc")
+list(APPEND libgav1_segmentation_map_test_sources
+            "${libgav1_source}/utils/segmentation_map_test.cc")
+list(APPEND libgav1_segmentation_test_sources
+            "${libgav1_source}/utils/segmentation_test.cc")
+list(APPEND libgav1_stack_test_sources "${libgav1_source}/utils/stack_test.cc")
+list(APPEND libgav1_symbol_decoder_context_test_sources
+            "${libgav1_source}/symbol_decoder_context_test.cc")
+list(APPEND libgav1_threadpool_test_sources
+            "${libgav1_source}/utils/threadpool_test.cc")
+list(APPEND libgav1_threading_strategy_test_sources
+            "${libgav1_source}/threading_strategy_test.cc")
+list(APPEND libgav1_unbounded_queue_test_sources
+            "${libgav1_source}/utils/unbounded_queue_test.cc")
+list(
+  APPEND libgav1_vector_test_sources "${libgav1_source}/utils/vector_test.cc")
+list(APPEND libgav1_version_test_sources "${libgav1_source}/version_test.cc")
+list(APPEND libgav1_warp_test_sources "${libgav1_source}/dsp/warp_test.cc")
+list(APPEND libgav1_warp_prediction_test_sources
+            "${libgav1_source}/warp_prediction_test.cc")
+
+macro(libgav1_add_tests_targets)
+  if(NOT LIBGAV1_ENABLE_TESTS)
+    message(
+      FATAL_ERROR
+        "This version of libgav1_add_tests_targets() should only be used with"
+        " LIBGAV1_ENABLE_TESTS set to true.")
+  endif()
+  libgav1_add_library(TEST
+                      NAME
+                      libgav1_gtest
+                      TYPE
+                      STATIC
+                      SOURCES
+                      "${libgav1_googletest}/googletest/src/gtest-all.cc"
+                      DEFINES
+                      ${libgav1_defines}
+                      INCLUDES
+                      ${libgav1_gtest_include_paths}
+                      ${libgav1_include_paths})
+
+  libgav1_add_library(TEST
+                      NAME
+                      libgav1_gtest_main
+                      TYPE
+                      STATIC
+                      SOURCES
+                      "${libgav1_googletest}/googletest/src/gtest_main.cc"
+                      DEFINES
+                      ${libgav1_defines}
+                      INCLUDES
+                      ${libgav1_gtest_include_paths}
+                      ${libgav1_include_paths})
+
+  if(use_absl_threading)
+    list(APPEND libgav1_common_test_absl_deps absl::synchronization)
+  endif()
+
+  libgav1_add_executable(TEST
+                         NAME
+                         array_2d_test
+                         SOURCES
+                         ${libgav1_array_2d_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         block_parameters_holder_test
+                         SOURCES
+                         ${libgav1_block_parameters_holder_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         blocking_counter_test
+                         SOURCES
+                         ${libgav1_blocking_counter_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  if(libgav1_have_avx2)
+    libgav1_add_executable(TEST
+                           NAME
+                           common_avx2_test
+                           SOURCES
+                           ${libgav1_common_avx2_test_sources}
+                           DEFINES
+                           ${libgav1_defines}
+                           INCLUDES
+                           ${libgav1_test_include_paths}
+                           LIB_DEPS
+                           ${libgav1_common_test_absl_deps}
+                           libgav1_gtest
+                           libgav1_gtest_main)
+  endif()
+
+  if(libgav1_have_neon)
+    libgav1_add_executable(TEST
+                           NAME
+                           common_neon_test
+                           SOURCES
+                           ${libgav1_common_neon_test_sources}
+                           DEFINES
+                           ${libgav1_defines}
+                           INCLUDES
+                           ${libgav1_test_include_paths}
+                           OBJLIB_DEPS
+                           libgav1_tests_block_utils
+                           LIB_DEPS
+                           ${libgav1_common_test_absl_deps}
+                           libgav1_gtest
+                           libgav1_gtest_main)
+  endif()
+
+  if(libgav1_have_sse4)
+    libgav1_add_executable(TEST
+                           NAME
+                           common_sse4_test
+                           SOURCES
+                           ${libgav1_common_sse4_test_sources}
+                           DEFINES
+                           ${libgav1_defines}
+                           INCLUDES
+                           ${libgav1_test_include_paths}
+                           LIB_DEPS
+                           ${libgav1_common_test_absl_deps}
+                           libgav1_gtest
+                           libgav1_gtest_main)
+  endif()
+
+  libgav1_add_executable(TEST
+                         NAME
+                         common_test
+                         SOURCES
+                         ${libgav1_common_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         cpu_test
+                         SOURCES
+                         ${libgav1_cpu_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         entropy_decoder_test
+                         SOURCES
+                         ${libgav1_entropy_decoder_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         file_reader_test
+                         SOURCES
+                         ${libgav1_file_reader_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_dsp
+                         libgav1_file_reader
+                         libgav1_utils
+                         libgav1_tests_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         file_reader_factory_test
+                         SOURCES
+                         ${libgav1_file_reader_factory_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_file_reader
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::memory
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         film_grain_test
+                         SOURCES
+                         ${libgav1_film_grain_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         memory_test
+                         SOURCES
+                         ${libgav1_memory_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         LIB_DEPS
+                         absl::base
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         queue_test
+                         SOURCES
+                         ${libgav1_queue_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         segmentation_map_test
+                         SOURCES
+                         ${libgav1_segmentation_map_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         segmentation_test
+                         SOURCES
+                         ${libgav1_segmentation_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         stack_test
+                         SOURCES
+                         ${libgav1_stack_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         symbol_decoder_context_test
+                         SOURCES
+                         ${libgav1_symbol_decoder_context_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         threadpool_test
+                         SOURCES
+                         ${libgav1_threadpool_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::synchronization
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         unbounded_queue_test
+                         SOURCES
+                         ${libgav1_unbounded_queue_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         tests_utils_test
+                         SOURCES
+                         ${libgav1_tests_utils_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         vector_test
+                         SOURCES
+                         ${libgav1_vector_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         version_test
+                         SOURCES
+                         ${libgav1_version_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         LIB_DEPS
+                         ${libgav1_dependency}
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_library(TEST
+                      NAME
+                      libgav1_tests_block_utils
+                      TYPE
+                      OBJECT
+                      SOURCES
+                      ${libgav1_tests_block_utils_sources}
+                      DEFINES
+                      ${libgav1_defines}
+                      INCLUDES
+                      ${libgav1_test_include_paths})
+
+  libgav1_add_library(TEST
+                      NAME
+                      libgav1_tests_utils
+                      TYPE
+                      OBJECT
+                      SOURCES
+                      ${libgav1_tests_utils_sources}
+                      DEFINES
+                      ${libgav1_defines}
+                      INCLUDES
+                      ${libgav1_test_include_paths})
+
+  libgav1_add_executable(TEST
+                         NAME
+                         average_blend_test
+                         SOURCES
+                         ${libgav1_average_blend_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         buffer_pool_test
+                         SOURCES
+                         ${libgav1_buffer_pool_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         cdef_test
+                         SOURCES
+                         ${libgav1_cdef_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         convolve_test
+                         SOURCES
+                         ${libgav1_convolve_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         c_decoder_test
+                         SOURCES
+                         ${libgav1_c_decoder_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_include_paths}
+                         LIB_DEPS
+                         ${libgav1_dependency})
+
+  libgav1_add_executable(TEST
+                         NAME
+                         c_version_test
+                         SOURCES
+                         ${libgav1_c_version_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_include_paths}
+                         LIB_DEPS
+                         ${libgav1_dependency})
+
+  libgav1_add_executable(TEST
+                         NAME
+                         decoder_test
+                         SOURCES
+                         ${libgav1_decoder_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         LIB_DEPS
+                         ${libgav1_dependency}
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         decoder_buffer_test
+                         SOURCES
+                         ${libgav1_decoder_buffer_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         LIB_DEPS
+                         ${libgav1_dependency}
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         distance_weighted_blend_test
+                         SOURCES
+                         ${libgav1_distance_weighted_blend_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         dsp_test
+                         SOURCES
+                         ${libgav1_dsp_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         file_writer_test
+                         SOURCES
+                         ${libgav1_file_writer_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_file_writer
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::memory
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         intrapred_cfl_test
+                         SOURCES
+                         ${libgav1_intrapred_cfl_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         intrapred_directional_test
+                         SOURCES
+                         ${libgav1_intrapred_directional_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         intrapred_filter_test
+                         SOURCES
+                         ${libgav1_intrapred_filter_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         intrapred_test
+                         SOURCES
+                         ${libgav1_intrapred_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         intra_edge_test
+                         SOURCES
+                         ${libgav1_intra_edge_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_tests_utils
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         inverse_transform_test
+                         SOURCES
+                         ${libgav1_inverse_transform_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         internal_frame_buffer_list_test
+                         SOURCES
+                         ${libgav1_internal_frame_buffer_list_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         loop_filter_test
+                         SOURCES
+                         ${libgav1_loop_filter_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         loop_restoration_test
+                         SOURCES
+                         ${libgav1_loop_restoration_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         mask_blend_test
+                         SOURCES
+                         ${libgav1_mask_blend_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         motion_field_projection_test
+                         SOURCES
+                         ${libgav1_motion_field_projection_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         motion_vector_search_test
+                         SOURCES
+                         ${libgav1_motion_vector_search_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         obmc_test
+                         SOURCES
+                         ${libgav1_obmc_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         obu_parser_test
+                         SOURCES
+                         ${libgav1_obu_parser_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         post_filter_test
+                         SOURCES
+                         ${libgav1_post_filter_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         prediction_mask_test
+                         SOURCES
+                         ${libgav1_prediction_mask_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::strings
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         quantizer_test
+                         SOURCES
+                         ${libgav1_quantizer_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         raw_bit_reader_test
+                         SOURCES
+                         ${libgav1_raw_bit_reader_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         reconstruction_test
+                         SOURCES
+                         ${libgav1_reconstruction_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         ${libgav1_test_objlib_deps}
+                         LIB_DEPS
+                         absl::strings
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         residual_buffer_pool_test
+                         SOURCES
+                         ${libgav1_residual_buffer_pool_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         ${libgav1_test_objlib_deps}
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         scan_test
+                         SOURCES
+                         ${libgav1_scan_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_utils
+                         ${libgav1_test_objlib_deps}
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         super_res_test
+                         SOURCES
+                         ${libgav1_super_res_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         threading_strategy_test
+                         SOURCES
+                         ${libgav1_threading_strategy_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         ${libgav1_test_objlib_deps}
+                         LIB_DEPS
+                         absl::str_format_internal
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         warp_test
+                         SOURCES
+                         ${libgav1_warp_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_block_utils
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         warp_prediction_test
+                         SOURCES
+                         ${libgav1_warp_prediction_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_utils
+                         LIB_DEPS
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+
+  libgav1_add_executable(TEST
+                         NAME
+                         weight_mask_test
+                         SOURCES
+                         ${libgav1_weight_mask_test_sources}
+                         DEFINES
+                         ${libgav1_defines}
+                         INCLUDES
+                         ${libgav1_test_include_paths}
+                         OBJLIB_DEPS
+                         libgav1_decoder
+                         libgav1_dsp
+                         libgav1_tests_utils
+                         libgav1_utils
+                         LIB_DEPS
+                         absl::str_format_internal
+                         absl::time
+                         ${libgav1_common_test_absl_deps}
+                         libgav1_gtest
+                         libgav1_gtest_main)
+endmacro()
diff --git a/tests/third_party/libvpx/LICENSE b/tests/third_party/libvpx/LICENSE
new file mode 100644
index 0000000..83ef339
--- /dev/null
+++ b/tests/third_party/libvpx/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2010, The WebM Project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google, nor the WebM Project, nor the names
+    of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written
+    permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/third_party/libvpx/acm_random.h b/tests/third_party/libvpx/acm_random.h
new file mode 100644
index 0000000..e8cfc9c
--- /dev/null
+++ b/tests/third_party/libvpx/acm_random.h
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE 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.
+ */
+
+#ifndef LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_ACM_RANDOM_H_
+#define LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_ACM_RANDOM_H_
+
+#include <cassert>
+#include <cstdint>
+#include <limits>
+
+#include "gtest/gtest.h"
+
+namespace libvpx_test {
+
+class ACMRandom {
+ public:
+  ACMRandom() : random_(DeterministicSeed()) {}
+
+  explicit ACMRandom(int seed) : random_(seed) {}
+
+  void Reset(int seed) { random_.Reseed(seed); }
+  uint16_t Rand16(void) {
+    const uint32_t value =
+        random_.Generate(testing::internal::Random::kMaxRange);
+    return (value >> 15) & 0xffff;
+  }
+
+  int32_t Rand20Signed(void) {
+    // Use 20 bits: values between 524287 and -524288.
+    const uint32_t value = random_.Generate(1048576);
+    return static_cast<int32_t>(value) - 524288;
+  }
+
+  int16_t Rand16Signed(void) {
+    // Use 16 bits: values between 32767 and -32768.
+    return static_cast<int16_t>(random_.Generate(65536));
+  }
+
+  int16_t Rand13Signed(void) {
+    // Use 13 bits: values between 4095 and -4096.
+    const uint32_t value = random_.Generate(8192);
+    return static_cast<int16_t>(value) - 4096;
+  }
+
+  int16_t Rand9Signed(void) {
+    // Use 9 bits: values between 255 (0x0FF) and -256 (0x100).
+    const uint32_t value = random_.Generate(512);
+    return static_cast<int16_t>(value) - 256;
+  }
+
+  uint8_t Rand8(void) {
+    const uint32_t value =
+        random_.Generate(testing::internal::Random::kMaxRange);
+    // There's a bit more entropy in the upper bits of this implementation.
+    return (value >> 23) & 0xff;
+  }
+
+  uint8_t Rand8Extremes(void) {
+    // Returns a random value near 0 or near 255, to better exercise
+    // saturation behavior.
+    const uint8_t r = Rand8();
+    return static_cast<uint8_t>((r < 128) ? r << 4 : r >> 4);
+  }
+
+  uint32_t RandRange(const uint32_t range) {
+    // testing::internal::Random::Generate provides values in the range
+    // testing::internal::Random::kMaxRange.
+    assert(range <= testing::internal::Random::kMaxRange);
+    return random_.Generate(range);
+  }
+
+  int PseudoUniform(int range) { return random_.Generate(range); }
+
+  int operator()(int n) { return PseudoUniform(n); }
+
+  static constexpr int DeterministicSeed(void) { return 0xbaba; }
+
+ private:
+  testing::internal::Random random_;
+};
+
+}  // namespace libvpx_test
+
+#endif  // LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_ACM_RANDOM_H_
diff --git a/tests/third_party/libvpx/md5_helper.h b/tests/third_party/libvpx/md5_helper.h
new file mode 100644
index 0000000..c97b590
--- /dev/null
+++ b/tests/third_party/libvpx/md5_helper.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE 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.
+ */
+
+#ifndef LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_HELPER_H_
+#define LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_HELPER_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#include "tests/third_party/libvpx/md5_utils.h"
+
+namespace libvpx_test {
+class MD5 {
+ public:
+  MD5() { MD5Init(&md5_); }
+
+  void Add(const uint8_t *data, size_t size) {
+    MD5Update(&md5_, data, static_cast<uint32_t>(size));
+  }
+
+  const char *Get(void) {
+    static const char hex[16] = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+    };
+    uint8_t tmp[16];
+    MD5Context ctx_tmp = md5_;
+
+    MD5Final(tmp, &ctx_tmp);
+    for (int i = 0; i < 16; i++) {
+      res_[i * 2 + 0] = hex[tmp[i] >> 4];
+      res_[i * 2 + 1] = hex[tmp[i] & 0xf];
+    }
+    res_[32] = 0;
+
+    return res_;
+  }
+
+ protected:
+  char res_[33];
+  MD5Context md5_;
+};
+
+}  // namespace libvpx_test
+
+#endif  // LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_HELPER_H_
diff --git a/tests/third_party/libvpx/md5_utils.cc b/tests/third_party/libvpx/md5_utils.cc
new file mode 100644
index 0000000..4638e54
--- /dev/null
+++ b/tests/third_party/libvpx/md5_utils.cc
@@ -0,0 +1,249 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions
+ *  - Ian Jackson <ian@chiark.greenend.org.uk>.
+ * Still in the public domain.
+ */
+
+#include "tests/third_party/libvpx/md5_utils.h"
+
+#include <cstring>
+
+static void byteSwap(UWORD32 *buf, unsigned words) {
+  md5byte *p;
+
+  /* Only swap bytes for big endian machines */
+  int i = 1;
+
+  if (*(char *)&i == 1) return;
+
+  p = (md5byte *)buf;
+
+  do {
+    *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
+             ((unsigned)p[1] << 8 | p[0]);
+    p += 4;
+  } while (--words);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx) {
+  ctx->buf[0] = 0x67452301;
+  ctx->buf[1] = 0xefcdab89;
+  ctx->buf[2] = 0x98badcfe;
+  ctx->buf[3] = 0x10325476;
+
+  ctx->bytes[0] = 0;
+  ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
+  UWORD32 t;
+
+  /* Update byte count */
+
+  t = ctx->bytes[0];
+
+  if ((ctx->bytes[0] = t + len) < t)
+    ctx->bytes[1]++; /* Carry from low to high */
+
+  t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+
+  if (t > len) {
+    memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+    return;
+  }
+
+  /* First chunk is an odd size */
+  memcpy((md5byte *)ctx->in + 64 - t, buf, t);
+  byteSwap(ctx->in, 16);
+  MD5Transform(ctx->buf, ctx->in);
+  buf += t;
+  len -= t;
+
+  /* Process data in 64-byte chunks */
+  while (len >= 64) {
+    memcpy(ctx->in, buf, 64);
+    byteSwap(ctx->in, 16);
+    MD5Transform(ctx->buf, ctx->in);
+    buf += 64;
+    len -= 64;
+  }
+
+  /* Handle any remaining bytes of data. */
+  memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(md5byte digest[16], struct MD5Context *ctx) {
+  int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+  md5byte *p = (md5byte *)ctx->in + count;
+
+  /* Set the first char of padding to 0x80.  There is always room. */
+  *p++ = 0x80;
+
+  /* Bytes of padding needed to make 56 bytes (-8..55) */
+  count = 56 - 1 - count;
+
+  if (count < 0) { /* Padding forces an extra block */
+    memset(p, 0, count + 8);
+    byteSwap(ctx->in, 16);
+    MD5Transform(ctx->buf, ctx->in);
+    p = (md5byte *)ctx->in;
+    count = 56;
+  }
+
+  memset(p, 0, count);
+  byteSwap(ctx->in, 14);
+
+  /* Append length in bits and transform */
+  ctx->in[14] = ctx->bytes[0] << 3;
+  ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+  MD5Transform(ctx->buf, ctx->in);
+
+  byteSwap(ctx->buf, 4);
+  memcpy(digest, ctx->buf, 16);
+  memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, in, s) \
+  (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x)
+
+#if defined(__clang__) && defined(__has_attribute)
+#if __has_attribute(no_sanitize)
+#define VPX_NO_UNSIGNED_OVERFLOW_CHECK \
+  __attribute__((no_sanitize("unsigned-integer-overflow")))
+#endif
+#endif
+
+#ifndef VPX_NO_UNSIGNED_OVERFLOW_CHECK
+#define VPX_NO_UNSIGNED_OVERFLOW_CHECK
+#endif
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+VPX_NO_UNSIGNED_OVERFLOW_CHECK void MD5Transform(UWORD32 buf[4],
+                                                 UWORD32 const in[16]) {
+  UWORD32 a, b, c, d;
+
+  a = buf[0];
+  b = buf[1];
+  c = buf[2];
+  d = buf[3];
+
+  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+#undef VPX_NO_UNSIGNED_OVERFLOW_CHECK
+
+#endif
diff --git a/tests/third_party/libvpx/md5_utils.h b/tests/third_party/libvpx/md5_utils.h
new file mode 100644
index 0000000..13be035
--- /dev/null
+++ b/tests/third_party/libvpx/md5_utils.h
@@ -0,0 +1,41 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions
+ *  - Ian Jackson <ian@chiark.greenend.org.uk>.
+ * Still in the public domain.
+ */
+
+#ifndef LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_UTILS_H_
+#define LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_UTILS_H_
+
+#define md5byte unsigned char
+#define UWORD32 unsigned int
+
+typedef struct MD5Context MD5Context;
+struct MD5Context {
+  UWORD32 buf[4];
+  UWORD32 bytes[2];
+  UWORD32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
+
+#endif  // LIBGAV1_TESTS_THIRD_PARTY_LIBVPX_MD5_UTILS_H_
diff --git a/tests/utils.cc b/tests/utils.cc
new file mode 100644
index 0000000..e91ea87
--- /dev/null
+++ b/tests/utils.cc
@@ -0,0 +1,197 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/utils.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+#include "src/dsp/dsp.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/utils/constants.h"
+#include "tests/third_party/libvpx/md5_helper.h"
+
+namespace libgav1 {
+namespace test_utils {
+namespace {
+
+int CloseFile(FILE* stream) { return fclose(stream); }
+
+bool ReadFileToString(absl::string_view file_name, std::string* const string) {
+  using FilePtr = std::unique_ptr<FILE, decltype(&CloseFile)>;
+  FilePtr file(fopen(std::string(file_name).c_str(), "rb"), &CloseFile);
+  if (file == nullptr) return false;
+
+  do {
+    int c = fgetc(file.get());
+    if (ferror(file.get()) != 0) return false;
+
+    if (c != EOF) {
+      string->append(1, static_cast<char>(c));
+    } else {
+      break;
+    }
+  } while (true);
+
+  return true;
+}
+
+}  // namespace
+
+void ResetDspTable(const int bitdepth) {
+  dsp::Dsp* const dsp = dsp_internal::GetWritableDspTable(bitdepth);
+  ASSERT_NE(dsp, nullptr);
+  memset(dsp, 0, sizeof(dsp::Dsp));
+}
+
+std::string GetMd5Sum(const void* bytes, size_t size) {
+  libvpx_test::MD5 md5;
+  md5.Add(static_cast<const uint8_t*>(bytes), size);
+  return md5.Get();
+}
+
+template <typename Pixel>
+std::string GetMd5Sum(const Pixel* block, int width, int height, int stride) {
+  libvpx_test::MD5 md5;
+  const Pixel* row = block;
+  for (int i = 0; i < height; ++i) {
+    md5.Add(reinterpret_cast<const uint8_t*>(row), width * sizeof(Pixel));
+    row += stride;
+  }
+  return md5.Get();
+}
+
+template std::string GetMd5Sum(const int8_t* block, int width, int height,
+                               int stride);
+template std::string GetMd5Sum(const int16_t* block, int width, int height,
+                               int stride);
+
+std::string GetMd5Sum(const DecoderBuffer& buffer) {
+  libvpx_test::MD5 md5;
+  const size_t pixel_size =
+      (buffer.bitdepth == 8) ? sizeof(uint8_t) : sizeof(uint16_t);
+  for (int plane = kPlaneY; plane < buffer.NumPlanes(); ++plane) {
+    const int height = buffer.displayed_height[plane];
+    const size_t width = buffer.displayed_width[plane] * pixel_size;
+    const int stride = buffer.stride[plane];
+    const uint8_t* plane_buffer = buffer.plane[plane];
+    for (int row = 0; row < height; ++row) {
+      md5.Add(plane_buffer, width);
+      plane_buffer += stride;
+    }
+  }
+  return md5.Get();
+}
+
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const void* data, size_t size,
+                    absl::Duration elapsed_time) {
+  const std::string digest = test_utils::GetMd5Sum(data, size);
+  printf("Mode %s[%31s]: %5d us     MD5: %s\n", name, function_name,
+         static_cast<int>(absl::ToInt64Microseconds(elapsed_time)),
+         digest.c_str());
+  EXPECT_STREQ(expected_digest, digest.c_str());
+}
+
+template <typename Pixel>
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const Pixel* block, int width,
+                    int height, int stride, absl::Duration elapsed_time) {
+  const std::string digest =
+      test_utils::GetMd5Sum(block, width, height, stride);
+  printf("Mode %s[%31s]: %5d us     MD5: %s\n", name, function_name,
+         static_cast<int>(absl::ToInt64Microseconds(elapsed_time)),
+         digest.c_str());
+  EXPECT_STREQ(expected_digest, digest.c_str());
+}
+
+template void CheckMd5Digest(const char name[], const char function_name[],
+                             const char expected_digest[], const int8_t* block,
+                             int width, int height, int stride,
+                             absl::Duration elapsed_time);
+template void CheckMd5Digest(const char name[], const char function_name[],
+                             const char expected_digest[], const int16_t* block,
+                             int width, int height, int stride,
+                             absl::Duration elapsed_time);
+
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const char actual_digest[],
+                    absl::Duration elapsed_time) {
+  printf("Mode %s[%31s]: %5d us     MD5: %s\n", name, function_name,
+         static_cast<int>(absl::ToInt64Microseconds(elapsed_time)),
+         actual_digest);
+  EXPECT_STREQ(expected_digest, actual_digest);
+}
+
+namespace {
+
+std::string GetSourceDir() {
+#if defined(__ANDROID__)
+  // Test files must be manually supplied. This path is frequently
+  // available on development devices.
+  return std::string("/data/local/tmp/tests/data");
+#elif defined(LIBGAV1_FLAGS_SRCDIR)
+  return std::string(LIBGAV1_FLAGS_SRCDIR) + "/tests/data";
+#else
+  return std::string(".");
+#endif  // defined(__ANDROID__)
+}
+
+std::string GetTempDir() {
+  const char* path = getenv("TMPDIR");
+  if (path == nullptr || path[0] == '\0') path = getenv("TEMP");
+  if (path != nullptr && path[0] != '\0') return std::string(path);
+
+#if defined(__ANDROID__)
+  return std::string("/data/local/tmp");
+#elif defined(LIBGAV1_FLAGS_TMPDIR)
+  return std::string(LIBGAV1_FLAGS_TMPDIR);
+#else
+  return std::string(".");
+#endif  // defined(__ANDROID__)
+}
+
+}  // namespace
+
+std::string GetTestInputFilePath(absl::string_view file_name) {
+  const char* const path = getenv("LIBGAV1_TEST_DATA_PATH");
+  if (path != nullptr && path[0] != '\0') {
+    return std::string(path) + "/" + std::string(file_name);
+  }
+  return GetSourceDir() + "/" + std::string(file_name);
+}
+
+std::string GetTestOutputFilePath(absl::string_view file_name) {
+  return GetTempDir() + "/" + std::string(file_name);
+}
+
+void GetTestData(absl::string_view file_name, const bool is_output_file,
+                 std::string* const output) {
+  ASSERT_NE(output, nullptr);
+  const std::string absolute_file_path = is_output_file
+                                             ? GetTestOutputFilePath(file_name)
+                                             : GetTestInputFilePath(file_name);
+
+  ASSERT_TRUE(ReadFileToString(absolute_file_path, output));
+}
+
+}  // namespace test_utils
+}  // namespace libgav1
diff --git a/tests/utils.h b/tests/utils.h
new file mode 100644
index 0000000..3394d64
--- /dev/null
+++ b/tests/utils.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2020 The libgav1 Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBGAV1_TESTS_UTILS_H_
+#define LIBGAV1_TESTS_UTILS_H_
+
+#include <cstddef>
+#include <new>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+#include "src/gav1/decoder_buffer.h"
+#include "src/utils/compiler_attributes.h"
+#include "src/utils/memory.h"
+#include "tests/third_party/libvpx/acm_random.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+#include <exception>
+#endif
+
+namespace libgav1 {
+namespace test_utils {
+
+enum { kAlternateDeterministicSeed = 0x9571 };
+static_assert(kAlternateDeterministicSeed !=
+                  libvpx_test::ACMRandom::DeterministicSeed(),
+              "");
+
+// Similar to libgav1::MaxAlignedAllocable, but retains the throwing versions
+// of new to support googletest allocations.
+// Note when building the source as C++17 or greater, gcc 11.2.0 may issue a
+// warning of the form:
+//   warning: 'void operator delete [](void*, std::align_val_t)' called on
+//     pointer returned from a mismatched allocation function
+//   note: returned from 'static void*
+//     libgav1::test_utils::MaxAlignedAllocable::operator new [](size_t)'
+// This is a false positive as this function calls
+// libgav1::MaxAlignedAllocable::operator new[](size, std::nothrow) which in
+// turn calls
+// void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&).
+// This is due to unbalanced inlining of the functions, so we force them to be
+// inlined.
+// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103993
+struct MaxAlignedAllocable {
+  // Class-specific allocation functions.
+  static LIBGAV1_ALWAYS_INLINE void* operator new(size_t size) {
+    void* const p =
+        libgav1::MaxAlignedAllocable::operator new(size, std::nothrow);
+#ifdef ABSL_HAVE_EXCEPTIONS
+    if (p == nullptr) throw std::bad_alloc();
+#endif
+    return p;
+  }
+  static LIBGAV1_ALWAYS_INLINE void* operator new[](size_t size) {
+    void* const p =
+        libgav1::MaxAlignedAllocable::operator new[](size, std::nothrow);
+#ifdef ABSL_HAVE_EXCEPTIONS
+    if (p == nullptr) throw std::bad_alloc();
+#endif
+    return p;
+  }
+
+  // Class-specific non-throwing allocation functions
+  static LIBGAV1_ALWAYS_INLINE void* operator new(
+      size_t size, const std::nothrow_t& tag) noexcept {
+    return libgav1::MaxAlignedAllocable::operator new(size, tag);
+  }
+  static LIBGAV1_ALWAYS_INLINE void* operator new[](
+      size_t size, const std::nothrow_t& tag) noexcept {
+    return libgav1::MaxAlignedAllocable::operator new[](size, tag);
+  }
+
+  // Class-specific deallocation functions.
+  static LIBGAV1_ALWAYS_INLINE void operator delete(void* ptr) noexcept {
+    libgav1::MaxAlignedAllocable::operator delete(ptr);
+  }
+  static LIBGAV1_ALWAYS_INLINE void operator delete[](void* ptr) noexcept {
+    libgav1::MaxAlignedAllocable::operator delete[](ptr);
+  }
+
+  // Only called if new (std::nothrow) is used and the constructor throws an
+  // exception.
+  static LIBGAV1_ALWAYS_INLINE void operator delete(
+      void* ptr, const std::nothrow_t& tag) noexcept {
+    libgav1::MaxAlignedAllocable::operator delete(ptr, tag);
+  }
+  // Only called if new[] (std::nothrow) is used and the constructor throws an
+  // exception.
+  static LIBGAV1_ALWAYS_INLINE void operator delete[](
+      void* ptr, const std::nothrow_t& tag) noexcept {
+    libgav1::MaxAlignedAllocable::operator delete[](ptr, tag);
+  }
+};
+
+// Clears dsp table entries for |bitdepth|. This function is not thread safe.
+void ResetDspTable(int bitdepth);
+
+//------------------------------------------------------------------------------
+// Gets human readable hexadecimal encoded MD5 sum from given data, block, or
+// frame buffer.
+
+std::string GetMd5Sum(const void* bytes, size_t size);
+template <typename Pixel>
+std::string GetMd5Sum(const Pixel* block, int width, int height, int stride);
+std::string GetMd5Sum(const DecoderBuffer& buffer);
+
+//------------------------------------------------------------------------------
+// Compares the md5 digest of |size| bytes of |data| with |expected_digest|.
+// Prints a log message with |name|, |function_name|, md5 digest and
+// |elapsed_time|. |name| and |function_name| are merely tags used for logging
+// and can be any meaningful string depending on the caller's context.
+
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const void* data, size_t size,
+                    absl::Duration elapsed_time);
+
+//------------------------------------------------------------------------------
+// Compares the md5 digest of |block| with |expected_digest|. The width, height,
+// and stride of |block| are |width|, |height|, and |stride|, respectively.
+// Prints a log message with |name|, |function_name|, md5 digest and
+// |elapsed_time|. |name| and |function_name| are merely tags used for logging
+// and can be any meaningful string depending on the caller's context.
+
+template <typename Pixel>
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const Pixel* block, int width,
+                    int height, int stride, absl::Duration elapsed_time);
+
+//------------------------------------------------------------------------------
+// Compares |actual_digest| with |expected_digest|. Prints a log message with
+// |name|, |function_name|, md5 digest and |elapsed_time|. |name| and
+// |function_name| are merely tags used for logging and can be any meaningful
+// string depending on the caller's context.
+
+void CheckMd5Digest(const char name[], const char function_name[],
+                    const char expected_digest[], const char actual_digest[],
+                    absl::Duration elapsed_time);
+
+//------------------------------------------------------------------------------
+// Reads the test data from |file_name| as a string into |output|. The
+// |is_output_file| argument controls the expansion of |file_name| to its full
+// path. When |is_output_file| is true GetTestData() reads from
+// utils.cc::GetTempDir(), and when it is false the file is read from
+// utils.cc::GetSourceDir().
+void GetTestData(absl::string_view file_name, bool is_output_file,
+                 std::string* output);
+
+//------------------------------------------------------------------------------
+// Returns the full path to |file_name| from libgav1/tests/data.
+std::string GetTestInputFilePath(absl::string_view file_name);
+
+//------------------------------------------------------------------------------
+// Returns the full path to |file_name| in a location where the file can be
+// opened for writing.
+std::string GetTestOutputFilePath(absl::string_view file_name);
+
+}  // namespace test_utils
+}  // namespace libgav1
+
+#endif  // LIBGAV1_TESTS_UTILS_H_
diff --git a/tests/utils_test.cc b/tests/utils_test.cc
new file mode 100644
index 0000000..1d5b598
--- /dev/null
+++ b/tests/utils_test.cc
@@ -0,0 +1,190 @@
+// Copyright 2020 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/utils.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <new>
+
+#include "absl/base/config.h"
+#include "gtest/gtest.h"
+#include "src/utils/memory.h"
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+#include <exception>
+#endif
+
+namespace libgav1 {
+namespace test_utils {
+namespace {
+
+constexpr size_t kMaxAllocableSize = 0x40000000;
+
+// Has a trivial default constructor that performs no action.
+struct SmallMaxAligned : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x;
+};
+
+// Has a nontrivial default constructor that initializes the data member.
+struct SmallMaxAlignedNontrivialConstructor : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x = 0;
+};
+
+// Has a trivial default constructor that performs no action.
+struct HugeMaxAligned : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1];
+};
+
+// Has a nontrivial default constructor that initializes the data member.
+struct HugeMaxAlignedNontrivialConstructor : public MaxAlignedAllocable {
+  alignas(kMaxAlignment) uint8_t x[kMaxAllocableSize + 1] = {};
+};
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+struct MaxAlignedThrowingConstructor : public MaxAlignedAllocable {
+  MaxAlignedThrowingConstructor() { throw std::exception(); }
+
+  uint8_t x;
+};
+#endif
+
+TEST(TestUtilsTest, TestMaxAlignedAllocable) {
+  {
+    // MaxAlignedAllocable::operator new (std::nothrow) is called.
+    std::unique_ptr<SmallMaxAligned> small(new (std::nothrow) SmallMaxAligned);
+    EXPECT_NE(small, nullptr);
+    // Note this check doesn't guarantee conformance as a suitably aligned
+    // address may be returned from any allocator.
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1),
+              0);
+    // MaxAlignedAllocable::operator delete is called.
+  }
+
+  {
+    // MaxAlignedAllocable::operator new is called.
+    std::unique_ptr<SmallMaxAligned> small(new SmallMaxAligned);
+    EXPECT_NE(small, nullptr);
+    // Note this check doesn't guarantee conformance as a suitably aligned
+    // address may be returned from any allocator.
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(small.get()) & (kMaxAlignment - 1),
+              0);
+    // MaxAlignedAllocable::operator delete is called.
+  }
+
+  {
+    // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+    std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
+        new (std::nothrow) SmallMaxAligned[10]);
+    EXPECT_NE(small_array_of_smalls, nullptr);
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
+                  (kMaxAlignment - 1),
+              0);
+    // MaxAlignedAllocable::operator delete[] is called.
+  }
+
+  {
+    // MaxAlignedAllocable::operator new[] is called.
+    std::unique_ptr<SmallMaxAligned[]> small_array_of_smalls(
+        new SmallMaxAligned[10]);
+    EXPECT_NE(small_array_of_smalls, nullptr);
+    EXPECT_EQ(reinterpret_cast<uintptr_t>(small_array_of_smalls.get()) &
+                  (kMaxAlignment - 1),
+              0);
+    // MaxAlignedAllocable::operator delete[] is called.
+  }
+
+  {
+    // MaxAlignedAllocable::operator new (std::nothrow) is called.
+    std::unique_ptr<HugeMaxAligned> huge(new (std::nothrow) HugeMaxAligned);
+    EXPECT_EQ(huge, nullptr);
+  }
+
+  {
+    // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+    std::unique_ptr<SmallMaxAligned[]> huge_array_of_smalls(
+        new (std::nothrow)
+            SmallMaxAligned[kMaxAllocableSize / sizeof(SmallMaxAligned) + 1]);
+    EXPECT_EQ(huge_array_of_smalls, nullptr);
+  }
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+  try {
+    // MaxAlignedAllocable::operator new (std::nothrow) is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete (std::nothrow) is called.
+    auto* always = new (std::nothrow) MaxAlignedThrowingConstructor;
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  try {
+    // MaxAlignedAllocable::operator new is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete is called.
+    auto* always = new MaxAlignedThrowingConstructor;
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  try {
+    // MaxAlignedAllocable::operator new[] (std::nothrow) is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete[] (std::nothrow) is called.
+    auto* always = new (std::nothrow) MaxAlignedThrowingConstructor[2];
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  try {
+    // MaxAlignedAllocable::operator new[] is called.
+    // The constructor throws an exception.
+    // MaxAlignedAllocable::operator delete[] is called.
+    auto* always = new MaxAlignedThrowingConstructor[2];
+    static_cast<void>(always);
+  } catch (...) {
+  }
+
+  // Note these calls are only safe with exceptions enabled as if the throwing
+  // operator new returns the object is expected to be valid. In this case an
+  // attempt to invoke the object's constructor on a nullptr may be made which
+  // is undefined behavior.
+  try {
+    // MaxAlignedAllocable::operator new is called.
+    std::unique_ptr<HugeMaxAlignedNontrivialConstructor> huge(
+        new HugeMaxAlignedNontrivialConstructor);
+    ADD_FAILURE() << "huge allocation should fail.";
+  } catch (...) {
+    SUCCEED();
+  }
+
+  try {
+    // MaxAlignedAllocable::operator new[] is called.
+    std::unique_ptr<SmallMaxAlignedNontrivialConstructor[]>
+        huge_array_of_smalls(
+            new SmallMaxAlignedNontrivialConstructor
+                [kMaxAllocableSize /
+                     sizeof(SmallMaxAlignedNontrivialConstructor) +
+                 1]);
+    ADD_FAILURE() << "huge_array_of_smalls allocation should fail.";
+  } catch (...) {
+    SUCCEED();
+  }
+#endif  // ABSL_HAVE_EXCEPTIONS
+}
+
+}  // namespace
+}  // namespace test_utils
+}  // namespace libgav1